From nobody Wed Nov 27 04:45:24 2024 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 D096815884A; Mon, 14 Oct 2024 09:08:23 +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=1728896906; cv=none; b=GoCKHpgkzf0DjdNuVDiMRCqjBCL6VzhiQt9LlQARNIf1bqQZZOJRB64V4REeQNA2zoIkDgZTuCy5XgFlinAVqpu80qxZVX0pETQ8zD9bbefhBBcEwVy5vPwH2orje8PnGVxBuP1YMCxYmN44/ehFHPXUsAQBxbMHZS2FG8eS7i8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1728896906; c=relaxed/simple; bh=b6DJKDF5kp8blfSADgPiODdHn5tbu5vrk0M7SFbrxnY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=i+HPJLF0I5IYRtBEr3E0WRh/kFziOgks2MsMoM00Nx6a4TjH1iUHeO1wTvVAm8eq6iqm75CSrk1smCFapkmy5kP6KC8tr3WNz87nr0ASdvS9i+OEqtYIJZBGYoQ40GRSPELVsh0qjGF3IYSZrxfG5rOqdiWi0NRvp/pnFtqurvs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=quicinc.com; spf=pass smtp.mailfrom=quicinc.com; dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com header.b=oDz+M8b/; arc=none smtp.client-ip=205.220.168.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=quicinc.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=quicinc.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com header.b="oDz+M8b/" Received: from pps.filterd (m0279866.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 49DErfNo011729; Mon, 14 Oct 2024 09:08:16 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= Oy/U18ydPsi0r6AT3GWnpo15pGspECJgZdzhxhBMq0g=; b=oDz+M8b/ivFukQnb MORoj/9mNMNVtEc9hrKK+LK7v0H337KLBDDfWB5ynQugpTV2j6u4gLvIqPeBgOYy HJy37heZH65zKN102OIHGQRdaNk34aboh3KxBsyB/kePVn/8T4To82EpoPnFHYr7 /hc5gNHRIIusmdKK9YVE+3aFj2V14m8caxUUsohUaBOdDZKxynMmhFK1bkJ0vKnv DWpteROwh7ZuLYt0qCm8ZFhlXGrm5LpYpYUvBV+hben+/qWp8m00SkxO/vMVA9QB V24yWY4ACQRsnqRwU8T2b5i+rHoWH44uFKZyJpCYPvUaVIPZl8nyl6RVcV2jVqpM UOkt7A== Received: from nalasppmta05.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 427jd8utdb-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 14 Oct 2024 09:08:15 +0000 (GMT) Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA05.qualcomm.com (8.18.1.2/8.18.1.2) with ESMTPS id 49E98Fvl002751 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 14 Oct 2024 09:08:15 GMT Received: from hu-dikshita-hyd.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.9; Mon, 14 Oct 2024 02:08:10 -0700 From: Dikshita Agarwal Date: Mon, 14 Oct 2024 14:37:29 +0530 Subject: [PATCH v4 08/28] media: iris: implement power management 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: <20241014-qcom-video-iris-v4-v4-8-c5eaa4e9ab9e@quicinc.com> References: <20241014-qcom-video-iris-v4-v4-0-c5eaa4e9ab9e@quicinc.com> In-Reply-To: <20241014-qcom-video-iris-v4-v4-0-c5eaa4e9ab9e@quicinc.com> To: Vikash Garodia , Abhinav Kumar , Mauro Carvalho Chehab , "Rob Herring" , Krzysztof Kozlowski , "Conor Dooley" , Philipp Zabel CC: Hans Verkuil , Sebastian Fricke , , , , , Dikshita Agarwal X-Mailer: b4 0.14.1 X-Developer-Signature: v=1; a=ed25519-sha256; t=1728896854; l=38478; i=quic_dikshita@quicinc.com; s=20240917; h=from:subject:message-id; bh=b6DJKDF5kp8blfSADgPiODdHn5tbu5vrk0M7SFbrxnY=; b=Ik78gpZTPE9MHX6HYdPDvyD/opp1hKVDX0/fN5u5SpgyeQ4fpP3sWkGeNdIjGOUqWPOTMcMtS GF7+bMNRIZkCYSAoUOQrhS67QB/LXU7FBcxdDrCxZ7yIJcDHeC5dU/T X-Developer-Key: i=quic_dikshita@quicinc.com; a=ed25519; pk=EEvKY6Ar1OI5SWf44FJ1Ebo1KuQEVbbf5UNPO+UHVhM= X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01a.na.qualcomm.com (10.47.209.196) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-GUID: 1hrl3_3-I6FzG1_hEnxCHLLvF51301dq X-Proofpoint-ORIG-GUID: 1hrl3_3-I6FzG1_hEnxCHLLvF51301dq X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.680,FMLib:17.12.60.29 definitions=2024-09-06_09,2024-09-06_01,2024-09-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 lowpriorityscore=0 phishscore=0 suspectscore=0 impostorscore=0 bulkscore=0 mlxscore=0 mlxlogscore=999 malwarescore=0 priorityscore=1501 adultscore=0 clxscore=1015 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2409260000 definitions=main-2410140066 Implement runtime power management for iris including platform specific power on/off sequence. Signed-off-by: Dikshita Agarwal --- drivers/media/platform/qcom/iris/Makefile | 3 + drivers/media/platform/qcom/iris/iris_core.c | 15 +- drivers/media/platform/qcom/iris/iris_core.h | 4 + drivers/media/platform/qcom/iris/iris_firmware.c | 5 + drivers/media/platform/qcom/iris/iris_firmware.h | 1 + drivers/media/platform/qcom/iris/iris_hfi_common.c | 62 ++++++ drivers/media/platform/qcom/iris/iris_hfi_common.h | 3 + .../platform/qcom/iris/iris_hfi_gen1_command.c | 11 + .../platform/qcom/iris/iris_hfi_gen1_defines.h | 5 + .../platform/qcom/iris/iris_hfi_gen2_command.c | 18 ++ .../platform/qcom/iris/iris_hfi_gen2_defines.h | 1 + .../platform/qcom/iris/iris_hfi_gen2_packet.c | 13 ++ .../platform/qcom/iris/iris_hfi_gen2_packet.h | 1 + drivers/media/platform/qcom/iris/iris_hfi_queue.c | 18 ++ .../platform/qcom/iris/iris_platform_common.h | 14 ++ .../platform/qcom/iris/iris_platform_sm8550.c | 9 + drivers/media/platform/qcom/iris/iris_probe.c | 53 +++++ drivers/media/platform/qcom/iris/iris_resources.c | 131 +++++++++++ drivers/media/platform/qcom/iris/iris_resources.h | 18 ++ drivers/media/platform/qcom/iris/iris_vidc.c | 8 + drivers/media/platform/qcom/iris/iris_vpu2.c | 11 + drivers/media/platform/qcom/iris/iris_vpu3.c | 84 +++++++ drivers/media/platform/qcom/iris/iris_vpu_common.c | 242 +++++++++++++++++= +++- drivers/media/platform/qcom/iris/iris_vpu_common.h | 11 + .../platform/qcom/iris/iris_vpu_register_defines.h | 17 ++ 25 files changed, 754 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/qcom/iris/Makefile b/drivers/media/plat= form/qcom/iris/Makefile index 76ca5287c49f..a5f290a8c4af 100644 --- a/drivers/media/platform/qcom/iris/Makefile +++ b/drivers/media/platform/qcom/iris/Makefile @@ -9,7 +9,10 @@ iris-objs +=3D iris_core.o \ iris_hfi_queue.o \ iris_platform_sm8550.o \ iris_probe.o \ + iris_resources.o \ iris_vidc.o \ + iris_vpu2.o \ + iris_vpu3.o \ iris_vpu_common.o \ =20 obj-$(CONFIG_VIDEO_QCOM_IRIS) +=3D iris.o diff --git a/drivers/media/platform/qcom/iris/iris_core.c b/drivers/media/p= latform/qcom/iris/iris_core.c index 7e19bdd0a19b..0fa0a3b549a2 100644 --- a/drivers/media/platform/qcom/iris/iris_core.c +++ b/drivers/media/platform/qcom/iris/iris_core.c @@ -3,6 +3,8 @@ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights res= erved. */ =20 +#include + #include "iris_core.h" #include "iris_firmware.h" #include "iris_state.h" @@ -10,11 +12,16 @@ =20 void iris_core_deinit(struct iris_core *core) { + pm_runtime_resume_and_get(core->dev); + mutex_lock(&core->lock); iris_fw_unload(core); + iris_vpu_power_off(core); iris_hfi_queues_deinit(core); core->state =3D IRIS_CORE_DEINIT; mutex_unlock(&core->lock); + + pm_runtime_put_sync(core->dev); } =20 static int iris_wait_for_system_response(struct iris_core *core) @@ -54,10 +61,14 @@ int iris_core_init(struct iris_core *core) if (ret) goto error; =20 - ret =3D iris_fw_load(core); + ret =3D iris_vpu_power_on(core); if (ret) goto error_queue_deinit; =20 + ret =3D iris_fw_load(core); + if (ret) + goto error_power_off; + ret =3D iris_vpu_boot_firmware(core); if (ret) goto error_unload_fw; @@ -72,6 +83,8 @@ int iris_core_init(struct iris_core *core) =20 error_unload_fw: iris_fw_unload(core); +error_power_off: + iris_vpu_power_off(core); error_queue_deinit: iris_hfi_queues_deinit(core); error: diff --git a/drivers/media/platform/qcom/iris/iris_core.h b/drivers/media/p= latform/qcom/iris/iris_core.h index 6c4d0bc0c36b..ae3523aa6a9b 100644 --- a/drivers/media/platform/qcom/iris/iris_core.h +++ b/drivers/media/platform/qcom/iris/iris_core.h @@ -7,11 +7,13 @@ #define _IRIS_CORE_H_ =20 #include +#include #include =20 #include "iris_hfi_common.h" #include "iris_hfi_queue.h" #include "iris_platform_common.h" +#include "iris_resources.h" #include "iris_state.h" =20 struct icc_info { @@ -52,6 +54,7 @@ struct icc_info { * @response_packet: a pointer to response packet from fw to driver * @header_id: id of packet header * @packet_id: id of packet + * @power: a structure for clock and bw information * @hfi_ops: iris hfi command ops * @hfi_response_ops: iris hfi response ops * @core_init_done: structure of signal completion for system response @@ -86,6 +89,7 @@ struct iris_core { u8 *response_packet; u32 header_id; u32 packet_id; + struct iris_core_power power; const struct iris_hfi_command_ops *hfi_ops; const struct iris_hfi_response_ops *hfi_response_ops; struct completion core_init_done; diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/med= ia/platform/qcom/iris/iris_firmware.c index 58a0f532b862..9c3a1ee66e23 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.c +++ b/drivers/media/platform/qcom/iris/iris_firmware.c @@ -106,3 +106,8 @@ int iris_fw_unload(struct iris_core *core) { return qcom_scm_pas_shutdown(core->iris_platform_data->pas_id); } + +int iris_set_hw_state(struct iris_core *core, bool resume) +{ + return qcom_scm_set_remote_state(resume, 0); +} diff --git a/drivers/media/platform/qcom/iris/iris_firmware.h b/drivers/med= ia/platform/qcom/iris/iris_firmware.h index 8d4f6b7f75c5..1550916c92a1 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.h +++ b/drivers/media/platform/qcom/iris/iris_firmware.h @@ -10,5 +10,6 @@ struct iris_core; =20 int iris_fw_load(struct iris_core *core); int iris_fw_unload(struct iris_core *core); +int iris_set_hw_state(struct iris_core *core, bool resume); =20 #endif diff --git a/drivers/media/platform/qcom/iris/iris_hfi_common.c b/drivers/m= edia/platform/qcom/iris/iris_hfi_common.c index a19b988c9a88..29f56c2bf74c 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_common.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_common.c @@ -3,6 +3,9 @@ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights res= erved. */ =20 +#include + +#include "iris_firmware.h" #include "iris_core.h" #include "iris_hfi_common.h" #include "iris_vpu_common.h" @@ -38,6 +41,7 @@ irqreturn_t iris_hfi_isr_handler(int irq, void *data) return IRQ_NONE; =20 mutex_lock(&core->lock); + pm_runtime_mark_last_busy(core->dev); iris_vpu_clear_interrupt(core); mutex_unlock(&core->lock); =20 @@ -48,3 +52,61 @@ irqreturn_t iris_hfi_isr_handler(int irq, void *data) =20 return IRQ_HANDLED; } + +int iris_hfi_pm_suspend(struct iris_core *core) +{ + int ret; + + ret =3D iris_vpu_prepare_pc(core); + if (ret) { + pm_runtime_mark_last_busy(core->dev); + ret =3D -EAGAIN; + goto error; + } + + ret =3D iris_set_hw_state(core, false); + if (ret) + goto error; + + iris_vpu_power_off(core); + + return 0; + +error: + dev_err(core->dev, "failed to suspend\n"); + + return ret; +} + +int iris_hfi_pm_resume(struct iris_core *core) +{ + const struct iris_hfi_command_ops *ops =3D core->hfi_ops; + int ret; + + ret =3D iris_vpu_power_on(core); + if (ret) + goto error; + + ret =3D iris_set_hw_state(core, true); + if (ret) + goto err_power_off; + + ret =3D iris_vpu_boot_firmware(core); + if (ret) + goto err_suspend_hw; + + ret =3D ops->sys_interframe_powercollapse(core); + if (ret) + goto err_suspend_hw; + + return 0; + +err_suspend_hw: + iris_set_hw_state(core, false); +err_power_off: + iris_vpu_power_off(core); +error: + dev_err(core->dev, "failed to resume\n"); + + return -EBUSY; +} diff --git a/drivers/media/platform/qcom/iris/iris_hfi_common.h b/drivers/m= edia/platform/qcom/iris/iris_hfi_common.h index c3d5b899cf60..e050b1ae90fe 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_common.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_common.h @@ -46,6 +46,7 @@ struct iris_hfi_command_ops { int (*sys_init)(struct iris_core *core); int (*sys_image_version)(struct iris_core *core); int (*sys_interframe_powercollapse)(struct iris_core *core); + int (*sys_pc_prep)(struct iris_core *core); }; =20 struct iris_hfi_response_ops { @@ -53,6 +54,8 @@ struct iris_hfi_response_ops { }; =20 int iris_hfi_core_init(struct iris_core *core); +int iris_hfi_pm_suspend(struct iris_core *core); +int iris_hfi_pm_resume(struct iris_core *core); =20 irqreturn_t iris_hfi_isr(int irq, void *data); irqreturn_t iris_hfi_isr_handler(int irq, void *data); diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c b/dri= vers/media/platform/qcom/iris/iris_hfi_gen1_command.c index 07007d8812ba..b2e76d1dcbf7 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c @@ -56,10 +56,21 @@ static int iris_hfi_gen1_sys_interframe_powercollapse(s= truct iris_core *core) return ret; } =20 +static int iris_hfi_gen1_sys_pc_prep(struct iris_core *core) +{ + struct hfi_sys_pc_prep_pkt pkt; + + pkt.hdr.size =3D sizeof(struct hfi_sys_pc_prep_pkt); + pkt.hdr.pkt_type =3D HFI_CMD_SYS_PC_PREP; + + return iris_hfi_queue_cmd_write_locked(core, &pkt, pkt.hdr.size); +} + static const struct iris_hfi_command_ops iris_hfi_gen1_command_ops =3D { .sys_init =3D iris_hfi_gen1_sys_init, .sys_image_version =3D iris_hfi_gen1_sys_image_version, .sys_interframe_powercollapse =3D iris_hfi_gen1_sys_interframe_powercolla= pse, + .sys_pc_prep =3D iris_hfi_gen1_sys_pc_prep, }; =20 void iris_hfi_gen1_command_ops_init(struct iris_core *core) diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h b/dri= vers/media/platform/qcom/iris/iris_hfi_gen1_defines.h index 5c07d6a29863..991d5a5dc792 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h @@ -12,6 +12,7 @@ #define HFI_ERR_NONE 0x0 =20 #define HFI_CMD_SYS_INIT 0x10001 +#define HFI_CMD_SYS_PC_PREP 0x10002 #define HFI_CMD_SYS_SET_PROPERTY 0x10005 #define HFI_CMD_SYS_GET_PROPERTY 0x10006 =20 @@ -48,6 +49,10 @@ struct hfi_sys_get_property_pkt { u32 data; }; =20 +struct hfi_sys_pc_prep_pkt { + struct hfi_pkt_hdr hdr; +}; + struct hfi_msg_event_notify_pkt { struct hfi_pkt_hdr hdr; u32 event_id; diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c b/dri= vers/media/platform/qcom/iris/iris_hfi_gen2_command.c index 5eaebe170214..f8cb1177ef54 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c @@ -68,10 +68,28 @@ static int iris_hfi_gen2_sys_interframe_powercollapse(s= truct iris_core *core) return ret; } =20 +static int iris_hfi_gen2_sys_pc_prep(struct iris_core *core) +{ + struct iris_hfi_header *hdr; + int ret; + + hdr =3D kzalloc(SYS_NO_PAYLOAD_PKT_SIZE, GFP_KERNEL); + if (!hdr) + return -ENOMEM; + + iris_hfi_gen2_packet_sys_pc_prep(core, hdr); + ret =3D iris_hfi_queue_cmd_write_locked(core, hdr, hdr->size); + + kfree(hdr); + + return ret; +} + static const struct iris_hfi_command_ops iris_hfi_gen2_command_ops =3D { .sys_init =3D iris_hfi_gen2_sys_init, .sys_image_version =3D iris_hfi_gen2_sys_image_version, .sys_interframe_powercollapse =3D iris_hfi_gen2_sys_interframe_powercolla= pse, + .sys_pc_prep =3D iris_hfi_gen2_sys_pc_prep, }; =20 void iris_hfi_gen2_command_ops_init(struct iris_core *core) diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h b/dri= vers/media/platform/qcom/iris/iris_hfi_gen2_defines.h index 3e3e4ddfe21f..4104479c7251 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h @@ -12,6 +12,7 @@ =20 #define HFI_CMD_BEGIN 0x01000000 #define HFI_CMD_INIT 0x01000001 +#define HFI_CMD_POWER_COLLAPSE 0x01000002 #define HFI_CMD_END 0x01FFFFFF =20 #define HFI_PROP_BEGIN 0x03000000 diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.c b/driv= ers/media/platform/qcom/iris/iris_hfi_gen2_packet.c index 986013aa62df..510d44408b41 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.c @@ -159,3 +159,16 @@ void iris_hfi_gen2_packet_sys_interframe_powercollapse= (struct iris_core *core, &payload, sizeof(u32)); } + +void iris_hfi_gen2_packet_sys_pc_prep(struct iris_core *core, struct iris_= hfi_header *hdr) +{ + iris_hfi_gen2_create_header(hdr, 0 /*session_id*/, core->header_id++); + + iris_hfi_gen2_create_packet(hdr, + HFI_CMD_POWER_COLLAPSE, + HFI_HOST_FLAGS_NONE, + HFI_PAYLOAD_NONE, + HFI_PORT_NONE, + core->packet_id++, + NULL, 0); +} diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.h b/driv= ers/media/platform/qcom/iris/iris_hfi_gen2_packet.h index eba109efeb76..163295783b7d 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.h @@ -65,5 +65,6 @@ void iris_hfi_gen2_packet_sys_init(struct iris_core *core= , struct iris_hfi_heade void iris_hfi_gen2_packet_image_version(struct iris_core *core, struct iri= s_hfi_header *hdr); void iris_hfi_gen2_packet_sys_interframe_powercollapse(struct iris_core *c= ore, struct iris_hfi_header *hdr); +void iris_hfi_gen2_packet_sys_pc_prep(struct iris_core *core, struct iris_= hfi_header *hdr); =20 #endif diff --git a/drivers/media/platform/qcom/iris/iris_hfi_queue.c b/drivers/me= dia/platform/qcom/iris/iris_hfi_queue.c index 136b1862c53f..9195715c5d5a 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_queue.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_queue.c @@ -3,6 +3,8 @@ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights res= erved. */ =20 +#include + #include "iris_core.h" #include "iris_hfi_queue.h" #include "iris_vpu_common.h" @@ -128,10 +130,26 @@ int iris_hfi_queue_cmd_write(struct iris_core *core, = void *pkt, u32 pkt_size) { int ret; =20 + ret =3D pm_runtime_resume_and_get(core->dev); + if (ret < 0) + goto exit; + mutex_lock(&core->lock); ret =3D iris_hfi_queue_cmd_write_locked(core, pkt, pkt_size); + if (ret) { + mutex_unlock(&core->lock); + goto exit; + } mutex_unlock(&core->lock); =20 + pm_runtime_mark_last_busy(core->dev); + pm_runtime_put_autosuspend(core->dev); + + return 0; + +exit: + pm_runtime_put_sync(core->dev); + return ret; } =20 diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/driv= ers/media/platform/qcom/iris/iris_platform_common.h index e188f6407934..ff11d28e853b 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_common.h +++ b/drivers/media/platform/qcom/iris/iris_platform_common.h @@ -10,6 +10,7 @@ struct iris_core; =20 #define IRIS_PAS_ID 9 #define HW_RESPONSE_TIMEOUT_VALUE (1000) /* milliseconds */ +#define AUTOSUSPEND_DELAY_VALUE (HW_RESPONSE_TIMEOUT_VALUE + 500) /* mil= liseconds */ =20 extern struct iris_platform_data sm8550_data; =20 @@ -41,10 +42,22 @@ struct ubwc_config_data { u32 bank_spreading; }; =20 +struct iris_core_power { + u64 clk_freq; + u64 icc_bw; +}; + +enum platform_pm_domain_type { + IRIS_CTRL_POWER_DOMAIN, + IRIS_HW_POWER_DOMAIN, +}; + struct iris_platform_data { void (*init_hfi_command_ops)(struct iris_core *core); void (*init_hfi_response_ops)(struct iris_core *core); struct iris_inst *(*get_instance)(void); + const struct vpu_ops *vpu_ops; + void (*set_preset_registers)(struct iris_core *core); const struct icc_info *icc_tbl; unsigned int icc_tbl_size; const char * const *pmdomain_tbl; @@ -62,6 +75,7 @@ struct iris_platform_data { u32 core_arch; u32 hw_response_timeout; struct ubwc_config_data *ubwc_config; + u32 num_vpp_pipe; }; =20 #endif diff --git a/drivers/media/platform/qcom/iris/iris_platform_sm8550.c b/driv= ers/media/platform/qcom/iris/iris_platform_sm8550.c index b749d355e8ad..b4c730c58558 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_sm8550.c +++ b/drivers/media/platform/qcom/iris/iris_platform_sm8550.c @@ -6,9 +6,15 @@ #include "iris_core.h" #include "iris_hfi_gen2.h" #include "iris_platform_common.h" +#include "iris_vpu_common.h" =20 #define VIDEO_ARCH_LX 1 =20 +static void iris_set_sm8550_preset_registers(struct iris_core *core) +{ + writel(0x0, core->reg_base + 0xB0088); +} + static const struct icc_info sm8550_icc_table[] =3D { { "cpu-cfg", 1000, 1000 }, { "video-mem", 1000, 15000000 }, @@ -47,6 +53,8 @@ struct iris_platform_data sm8550_data =3D { .get_instance =3D iris_hfi_gen2_get_instance, .init_hfi_command_ops =3D iris_hfi_gen2_command_ops_init, .init_hfi_response_ops =3D iris_hfi_gen2_response_ops_init, + .vpu_ops =3D &iris_vpu3_ops, + .set_preset_registers =3D iris_set_sm8550_preset_registers, .icc_tbl =3D sm8550_icc_table, .icc_tbl_size =3D ARRAY_SIZE(sm8550_icc_table), .clk_rst_tbl =3D sm8550_clk_reset_table, @@ -64,4 +72,5 @@ struct iris_platform_data sm8550_data =3D { .core_arch =3D VIDEO_ARCH_LX, .hw_response_timeout =3D HW_RESPONSE_TIMEOUT_VALUE, .ubwc_config =3D &ubwc_config_sm8550, + .num_vpp_pipe =3D 4, }; diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/= platform/qcom/iris/iris_probe.c index 027009d84c2b..e6995af1e3a6 100644 --- a/drivers/media/platform/qcom/iris/iris_probe.c +++ b/drivers/media/platform/qcom/iris/iris_probe.c @@ -8,6 +8,7 @@ #include #include #include +#include #include =20 #include "iris_core.h" @@ -253,6 +254,12 @@ static int iris_probe(struct platform_device *pdev) dma_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); dma_set_seg_boundary(&pdev->dev, DMA_BIT_MASK(32)); =20 + pm_runtime_set_autosuspend_delay(core->dev, AUTOSUSPEND_DELAY_VALUE); + pm_runtime_use_autosuspend(core->dev); + ret =3D devm_pm_runtime_enable(core->dev); + if (ret) + goto err_vdev_unreg; + return 0; =20 err_vdev_unreg: @@ -263,6 +270,51 @@ static int iris_probe(struct platform_device *pdev) return ret; } =20 +static int iris_pm_suspend(struct device *dev) +{ + struct iris_core *core; + int ret; + + core =3D dev_get_drvdata(dev); + + mutex_lock(&core->lock); + if (core->state !=3D IRIS_CORE_INIT) + goto exit; + + ret =3D iris_hfi_pm_suspend(core); + +exit: + mutex_unlock(&core->lock); + + return ret; +} + +static int iris_pm_resume(struct device *dev) +{ + struct iris_core *core; + int ret =3D 0; + + core =3D dev_get_drvdata(dev); + + mutex_lock(&core->lock); + if (core->state !=3D IRIS_CORE_INIT) + goto exit; + + ret =3D iris_hfi_pm_resume(core); + pm_runtime_mark_last_busy(core->dev); + +exit: + mutex_unlock(&core->lock); + + return ret; +} + +static const struct dev_pm_ops iris_pm_ops =3D { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(iris_pm_suspend, iris_pm_resume, NULL) +}; + static const struct of_device_id iris_dt_match[] =3D { { .compatible =3D "qcom,sm8550-iris", @@ -278,6 +330,7 @@ static struct platform_driver qcom_iris_driver =3D { .driver =3D { .name =3D "qcom-iris", .of_match_table =3D iris_dt_match, + .pm =3D &iris_pm_ops, }, }; =20 diff --git a/drivers/media/platform/qcom/iris/iris_resources.c b/drivers/me= dia/platform/qcom/iris/iris_resources.c new file mode 100644 index 000000000000..cf32f268b703 --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_resources.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights res= erved. + */ + +#include +#include +#include +#include +#include +#include + +#include "iris_core.h" +#include "iris_resources.h" + +#define BW_THRESHOLD 50000 + +int iris_set_icc_bw(struct iris_core *core, unsigned long icc_bw) +{ + unsigned long bw_kbps =3D 0, bw_prev =3D 0; + const struct icc_info *icc_tbl; + int ret =3D 0, i; + + icc_tbl =3D core->iris_platform_data->icc_tbl; + + for (i =3D 0; i < core->icc_count; i++) { + if (!strcmp(core->icc_tbl[i].name, "video-mem")) { + bw_kbps =3D icc_bw; + bw_prev =3D core->power.icc_bw; + + bw_kbps =3D clamp_t(typeof(bw_kbps), bw_kbps, + icc_tbl[i].bw_min_kbps, icc_tbl[i].bw_max_kbps); + + if (abs(bw_kbps - bw_prev) < BW_THRESHOLD && bw_prev) + return ret; + + core->icc_tbl[i].avg_bw =3D bw_kbps; + + core->power.icc_bw =3D bw_kbps; + break; + } + } + + return icc_bulk_set_bw(core->icc_count, core->icc_tbl); +} + +int iris_unset_icc_bw(struct iris_core *core) +{ + u32 i; + + core->power.icc_bw =3D 0; + + for (i =3D 0; i < core->icc_count; i++) { + core->icc_tbl[i].avg_bw =3D 0; + core->icc_tbl[i].peak_bw =3D 0; + } + + return icc_bulk_set_bw(core->icc_count, core->icc_tbl); +} + +int iris_enable_power_domains(struct iris_core *core, struct device *pd_de= v) +{ + int ret; + + ret =3D dev_pm_opp_set_rate(core->dev, ULONG_MAX); + if (ret) + return ret; + + ret =3D pm_runtime_get_sync(pd_dev); + if (ret < 0) + return ret; + + return ret; +} + +int iris_disable_power_domains(struct iris_core *core, struct device *pd_d= ev) +{ + int ret; + + ret =3D dev_pm_opp_set_rate(core->dev, 0); + if (ret) + return ret; + + pm_runtime_put_sync(pd_dev); + + return 0; +} + +static struct clk *iris_get_clk_by_type(struct iris_core *core, enum platf= orm_clk_type clk_type) +{ + const struct platform_clk_data *clk_tbl; + u32 clk_cnt, i, j; + + clk_tbl =3D core->iris_platform_data->clk_tbl; + clk_cnt =3D core->iris_platform_data->clk_tbl_size; + + for (i =3D 0; i < clk_cnt; i++) { + if (clk_tbl[i].clk_type =3D=3D clk_type) { + for (j =3D 0; core->clock_tbl && j < core->clk_count; j++) { + if (!strcmp(core->clock_tbl[j].id, clk_tbl[i].clk_name)) + return core->clock_tbl[j].clk; + } + } + } + + return NULL; +} + +int iris_prepare_enable_clock(struct iris_core *core, enum platform_clk_ty= pe clk_type) +{ + struct clk *clock; + + clock =3D iris_get_clk_by_type(core, clk_type); + if (!clock) + return -EINVAL; + + return clk_prepare_enable(clock); +} + +int iris_disable_unprepare_clock(struct iris_core *core, enum platform_clk= _type clk_type) +{ + struct clk *clock; + + clock =3D iris_get_clk_by_type(core, clk_type); + if (!clock) + return -EINVAL; + + clk_disable_unprepare(clock); + + return 0; +} diff --git a/drivers/media/platform/qcom/iris/iris_resources.h b/drivers/me= dia/platform/qcom/iris/iris_resources.h new file mode 100644 index 000000000000..af32b310a0aa --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_resources.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights res= erved. + */ + +#ifndef _IRIS_RESOURCES_H_ +#define _IRIS_RESOURCES_H_ + +struct iris_core; + +int iris_enable_power_domains(struct iris_core *core, struct device *pd_de= v); +int iris_disable_power_domains(struct iris_core *core, struct device *pd_d= ev); +int iris_unset_icc_bw(struct iris_core *core); +int iris_set_icc_bw(struct iris_core *core, unsigned long icc_bw); +int iris_disable_unprepare_clock(struct iris_core *core, enum platform_clk= _type clk_type); +int iris_prepare_enable_clock(struct iris_core *core, enum platform_clk_ty= pe clk_type); + +#endif diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/p= latform/qcom/iris/iris_vidc.c index 5dd0ccbaa2fb..b8654e73f516 100644 --- a/drivers/media/platform/qcom/iris/iris_vidc.c +++ b/drivers/media/platform/qcom/iris/iris_vidc.c @@ -3,6 +3,7 @@ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights res= erved. */ =20 +#include #include #include =20 @@ -81,12 +82,19 @@ int iris_open(struct file *filp) struct iris_inst *inst; int ret; =20 + ret =3D pm_runtime_resume_and_get(core->dev); + if (ret < 0) + return ret; + ret =3D iris_core_init(core); if (ret) { dev_err(core->dev, "core init failed\n"); + pm_runtime_put_sync(core->dev); return ret; } =20 + pm_runtime_put_sync(core->dev); + inst =3D core->iris_platform_data->get_instance(); if (!inst) return -ENOMEM; diff --git a/drivers/media/platform/qcom/iris/iris_vpu2.c b/drivers/media/p= latform/qcom/iris/iris_vpu2.c new file mode 100644 index 000000000000..bd8427411576 --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_vpu2.c @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights res= erved. + */ + +#include "iris_instance.h" +#include "iris_vpu_common.h" + +const struct vpu_ops iris_vpu2_ops =3D { + .power_off_hw =3D iris_vpu_power_off_hw, +}; diff --git a/drivers/media/platform/qcom/iris/iris_vpu3.c b/drivers/media/p= latform/qcom/iris/iris_vpu3.c new file mode 100644 index 000000000000..10599f1fa789 --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_vpu3.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights res= erved. + */ + +#include + +#include "iris_instance.h" +#include "iris_vpu_common.h" +#include "iris_vpu_register_defines.h" + +#define AON_MVP_NOC_RESET 0x0001F000 + +#define WRAPPER_CORE_CLOCK_CONFIG (WRAPPER_BASE_OFFS + 0x88) +#define CORE_CLK_RUN 0x0 + +#define CPU_CS_AHB_BRIDGE_SYNC_RESET (CPU_CS_BASE_OFFS + 0x160) +#define CORE_BRIDGE_SW_RESET BIT(0) +#define CORE_BRIDGE_HW_RESET_DISABLE BIT(1) + +#define AON_WRAPPER_MVP_NOC_RESET_REQ (AON_MVP_NOC_RESET + 0x000) +#define VIDEO_NOC_RESET_REQ (BIT(0) | BIT(1)) + +#define AON_WRAPPER_MVP_NOC_RESET_ACK (AON_MVP_NOC_RESET + 0x004) + +#define VCODEC_SS_IDLE_STATUSN (VCODEC_BASE_OFFS + 0x70) + +static bool iris_vpu3_hw_power_collapsed(struct iris_core *core) +{ + u32 value, pwr_status; + + value =3D readl(core->reg_base + WRAPPER_CORE_POWER_STATUS); + pwr_status =3D value & BIT(1); + + return pwr_status ? false : true; +} + +static void iris_vpu3_power_off_hardware(struct iris_core *core) +{ + u32 reg_val =3D 0, value, i; + int ret; + + if (iris_vpu3_hw_power_collapsed(core)) + goto disable_power; + + dev_err(core->dev, "video hw is power on\n"); + + value =3D readl(core->reg_base + WRAPPER_CORE_CLOCK_CONFIG); + if (value) + writel(CORE_CLK_RUN, core->reg_base + WRAPPER_CORE_CLOCK_CONFIG); + + for (i =3D 0; i < core->iris_platform_data->num_vpp_pipe; i++) { + ret =3D readl_poll_timeout(core->reg_base + VCODEC_SS_IDLE_STATUSN + 4 *= i, + reg_val, reg_val & 0x400000, 2000, 20000); + if (ret) + goto disable_power; + } + + writel(VIDEO_NOC_RESET_REQ, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_RE= Q); + + ret =3D readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_RESET_ACK, + reg_val, reg_val & 0x3, 200, 2000); + if (ret) + goto disable_power; + + writel(0x0, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_REQ); + + ret =3D readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_RESET_ACK, + reg_val, !(reg_val & 0x3), 200, 2000); + if (ret) + goto disable_power; + + writel(CORE_BRIDGE_SW_RESET | CORE_BRIDGE_HW_RESET_DISABLE, + core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); + writel(CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + CPU_CS_AHB_BRIDGE_S= YNC_RESET); + writel(0x0, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); + +disable_power: + iris_vpu_power_off_hw(core); +} + +const struct vpu_ops iris_vpu3_ops =3D { + .power_off_hw =3D iris_vpu3_power_off_hardware, +}; diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.c b/drivers/m= edia/platform/qcom/iris/iris_vpu_common.c index f271068cd838..fe9896d66848 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_common.c +++ b/drivers/media/platform/qcom/iris/iris_vpu_common.c @@ -4,13 +4,16 @@ */ =20 #include +#include +#include =20 #include "iris_core.h" #include "iris_vpu_common.h" +#include "iris_vpu_register_defines.h" =20 -#define CPU_BASE_OFFS 0x000A0000 +#define WRAPPER_TZ_BASE_OFFS 0x000C0000 +#define AON_BASE_OFFS 0x000E0000 =20 -#define CPU_CS_BASE_OFFS (CPU_BASE_OFFS) #define CPU_IC_BASE_OFFS (CPU_BASE_OFFS) =20 #define CPU_CS_A2HSOFTINTCLR (CPU_CS_BASE_OFFS + 0x1C) @@ -21,6 +24,7 @@ =20 #define CTRL_INIT_IDLE_MSG_BMSK 0x40000000 #define CTRL_ERROR_STATUS__M 0xfe +#define CTRL_STATUS_PC_READY 0x100 =20 #define QTBL_INFO (CPU_CS_BASE_OFFS + 0x50) #define QTBL_ENABLE BIT(0) @@ -35,15 +39,47 @@ #define HOST2XTENSA_INTR_ENABLE BIT(0) =20 #define CPU_CS_X2RPMH (CPU_CS_BASE_OFFS + 0x168) +#define MSK_SIGNAL_FROM_TENSILICA BIT(0) +#define MSK_CORE_POWER_ON BIT(1) =20 #define CPU_IC_SOFTINT (CPU_IC_BASE_OFFS + 0x150) #define CPU_IC_SOFTINT_H2A_SHFT 0x0 =20 -#define WRAPPER_BASE_OFFS 0x000B0000 #define WRAPPER_INTR_STATUS (WRAPPER_BASE_OFFS + 0x0C) #define WRAPPER_INTR_STATUS_A2HWD_BMSK BIT(3) #define WRAPPER_INTR_STATUS_A2H_BMSK BIT(2) =20 +#define WRAPPER_INTR_MASK (WRAPPER_BASE_OFFS + 0x10) +#define WRAPPER_INTR_MASK_A2HWD_BMSK BIT(3) +#define WRAPPER_INTR_MASK_A2HCPU_BMSK BIT(2) + +#define WRAPPER_DEBUG_BRIDGE_LPI_CONTROL (WRAPPER_BASE_OFFS + 0x54) +#define WRAPPER_DEBUG_BRIDGE_LPI_STATUS (WRAPPER_BASE_OFFS + 0x58) +#define WRAPPER_IRIS_CPU_NOC_LPI_CONTROL (WRAPPER_BASE_OFFS + 0x5C) +#define WRAPPER_IRIS_CPU_NOC_LPI_STATUS (WRAPPER_BASE_OFFS + 0x60) + +#define WRAPPER_TZ_CPU_STATUS (WRAPPER_TZ_BASE_OFFS + 0x10) +#define WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG (WRAPPER_TZ_BASE_OFFS + 0x14) +#define CTL_AXI_CLK_HALT BIT(0) +#define CTL_CLK_HALT BIT(1) + +#define WRAPPER_TZ_QNS4PDXFIFO_RESET (WRAPPER_TZ_BASE_OFFS + 0x18) +#define RESET_HIGH BIT(0) + +#define AON_WRAPPER_MVP_NOC_LPI_CONTROL (AON_BASE_OFFS) +#define REQ_POWER_DOWN_PREP BIT(0) + +#define AON_WRAPPER_MVP_NOC_LPI_STATUS (AON_BASE_OFFS + 0x4) + +static void iris_vpu_interrupt_init(struct iris_core *core) +{ + u32 mask_val; + + mask_val =3D readl(core->reg_base + WRAPPER_INTR_MASK); + mask_val &=3D ~(WRAPPER_INTR_MASK_A2HWD_BMSK | + WRAPPER_INTR_MASK_A2HCPU_BMSK); + writel(mask_val, core->reg_base + WRAPPER_INTR_MASK); +} =20 static void iris_vpu_setup_ucregion_memory_map(struct iris_core *core) { @@ -131,3 +167,203 @@ int iris_vpu_watchdog(struct iris_core *core, u32 int= r_status) =20 return 0; } + +int iris_vpu_prepare_pc(struct iris_core *core) +{ + u32 wfi_status, idle_status, pc_ready; + u32 ctrl_status, val =3D 0; + int ret; + + ctrl_status =3D readl(core->reg_base + CTRL_STATUS); + pc_ready =3D ctrl_status & CTRL_STATUS_PC_READY; + idle_status =3D ctrl_status & BIT(30); + if (pc_ready) + return 0; + + wfi_status =3D readl(core->reg_base + WRAPPER_TZ_CPU_STATUS); + wfi_status &=3D BIT(0); + if (!wfi_status || !idle_status) + goto skip_power_off; + + ret =3D core->hfi_ops->sys_pc_prep(core); + if (ret) + goto skip_power_off; + + ret =3D readl_poll_timeout(core->reg_base + CTRL_STATUS, val, + val & CTRL_STATUS_PC_READY, 250, 2500); + if (ret) + goto skip_power_off; + + ret =3D readl_poll_timeout(core->reg_base + WRAPPER_TZ_CPU_STATUS, + val, val & BIT(0), 250, 2500); + if (ret) + goto skip_power_off; + + return 0; + +skip_power_off: + ctrl_status =3D readl(core->reg_base + CTRL_STATUS); + wfi_status =3D readl(core->reg_base + WRAPPER_TZ_CPU_STATUS); + wfi_status &=3D BIT(0); + dev_err(core->dev, "skip power collapse, wfi=3D%#x, idle=3D%#x, pcr=3D%#x= , ctrl=3D%#x)\n", + wfi_status, idle_status, pc_ready, ctrl_status); + + return -EAGAIN; +} + +static int iris_vpu_power_off_controller(struct iris_core *core) +{ + u32 val =3D 0; + int ret; + + writel(MSK_SIGNAL_FROM_TENSILICA | MSK_CORE_POWER_ON, core->reg_base + CP= U_CS_X2RPMH); + + writel(REQ_POWER_DOWN_PREP, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONT= ROL); + + ret =3D readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_LPI_STATU= S, + val, val & BIT(0), 200, 2000); + if (ret) + goto disable_power; + + writel(REQ_POWER_DOWN_PREP, core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_CON= TROL); + + ret =3D readl_poll_timeout(core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_STAT= US, + val, val & BIT(0), 200, 2000); + if (ret) + goto disable_power; + + writel(0x0, core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_CONTROL); + + ret =3D readl_poll_timeout(core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_STAT= US, + val, val =3D=3D 0, 200, 2000); + if (ret) + goto disable_power; + + writel(CTL_AXI_CLK_HALT | CTL_CLK_HALT, + core->reg_base + WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG); + writel(RESET_HIGH, core->reg_base + WRAPPER_TZ_QNS4PDXFIFO_RESET); + writel(0x0, core->reg_base + WRAPPER_TZ_QNS4PDXFIFO_RESET); + writel(0x0, core->reg_base + WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG); + +disable_power: + iris_disable_unprepare_clock(core, IRIS_CTRL_CLK); + iris_disable_unprepare_clock(core, IRIS_AXI_CLK); + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_PO= WER_DOMAIN]); + + return 0; +} + +void iris_vpu_power_off_hw(struct iris_core *core) +{ + dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]= , false); + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWE= R_DOMAIN]); + iris_disable_unprepare_clock(core, IRIS_HW_CLK); +} + +void iris_vpu_power_off(struct iris_core *core) +{ + dev_pm_opp_set_rate(core->dev, 0); + core->iris_platform_data->vpu_ops->power_off_hw(core); + iris_vpu_power_off_controller(core); + iris_unset_icc_bw(core); + + if (!iris_vpu_watchdog(core, core->intr_status)) + disable_irq_nosync(core->irq); +} + +static int iris_vpu_power_on_controller(struct iris_core *core) +{ + u32 rst_tbl_size =3D core->iris_platform_data->clk_rst_tbl_size; + int ret; + + ret =3D iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_= CTRL_POWER_DOMAIN]); + if (ret) + return ret; + + ret =3D reset_control_bulk_reset(rst_tbl_size, core->resets); + if (ret) + goto err_disable_power; + + ret =3D iris_prepare_enable_clock(core, IRIS_AXI_CLK); + if (ret) + goto err_disable_power; + + ret =3D iris_prepare_enable_clock(core, IRIS_CTRL_CLK); + if (ret) + goto err_disable_clock; + + return 0; + +err_disable_clock: + iris_disable_unprepare_clock(core, IRIS_AXI_CLK); +err_disable_power: + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_PO= WER_DOMAIN]); + + return ret; +} + +static int iris_vpu_power_on_hw(struct iris_core *core) +{ + int ret; + + ret =3D iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_= HW_POWER_DOMAIN]); + if (ret) + return ret; + + ret =3D iris_prepare_enable_clock(core, IRIS_HW_CLK); + if (ret) + goto err_disable_power; + + ret =3D dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs[IRIS_HW_POWER= _DOMAIN], true); + if (ret) + goto err_disable_clock; + + return 0; + +err_disable_clock: + iris_disable_unprepare_clock(core, IRIS_HW_CLK); +err_disable_power: + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWE= R_DOMAIN]); + + return ret; +} + +int iris_vpu_power_on(struct iris_core *core) +{ + u32 freq; + int ret; + + ret =3D iris_set_icc_bw(core, INT_MAX); + if (ret) + goto err; + + ret =3D iris_vpu_power_on_controller(core); + if (ret) + goto err_unvote_icc; + + ret =3D iris_vpu_power_on_hw(core); + if (ret) + goto err_power_off_ctrl; + + freq =3D core->power.clk_freq ? core->power.clk_freq : + (u32)ULONG_MAX; + + dev_pm_opp_set_rate(core->dev, freq); + + core->iris_platform_data->set_preset_registers(core); + + iris_vpu_interrupt_init(core); + core->intr_status =3D 0; + enable_irq(core->irq); + + return 0; + +err_power_off_ctrl: + iris_vpu_power_off_controller(core); +err_unvote_icc: + iris_unset_icc_bw(core); +err: + dev_err(core->dev, "power on failed\n"); + + return ret; +} diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.h b/drivers/m= edia/platform/qcom/iris/iris_vpu_common.h index 706b207bc295..525bbb52dd79 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_common.h +++ b/drivers/media/platform/qcom/iris/iris_vpu_common.h @@ -8,9 +8,20 @@ =20 struct iris_core; =20 +extern const struct vpu_ops iris_vpu2_ops; +extern const struct vpu_ops iris_vpu3_ops; + +struct vpu_ops { + void (*power_off_hw)(struct iris_core *core); +}; + int iris_vpu_boot_firmware(struct iris_core *core); void iris_vpu_raise_interrupt(struct iris_core *core); void iris_vpu_clear_interrupt(struct iris_core *core); int iris_vpu_watchdog(struct iris_core *core, u32 intr_status); +int iris_vpu_prepare_pc(struct iris_core *core); +int iris_vpu_power_on(struct iris_core *core); +void iris_vpu_power_off_hw(struct iris_core *core); +void iris_vpu_power_off(struct iris_core *core); =20 #endif diff --git a/drivers/media/platform/qcom/iris/iris_vpu_register_defines.h b= /drivers/media/platform/qcom/iris/iris_vpu_register_defines.h new file mode 100644 index 000000000000..818c81048fe5 --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_vpu_register_defines.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights res= erved. + */ + +#ifndef _IRIS_VPU_REGISTER_DEFINES_H_ +#define _IRIS_VPU_REGISTER_DEFINES_H_ + +#define VCODEC_BASE_OFFS 0x00000000 +#define CPU_BASE_OFFS 0x000A0000 +#define WRAPPER_BASE_OFFS 0x000B0000 + +#define CPU_CS_BASE_OFFS (CPU_BASE_OFFS) + +#define WRAPPER_CORE_POWER_STATUS (WRAPPER_BASE_OFFS + 0x80) + +#endif --=20 2.34.1