From patchwork Thu Dec 12 11:51:30 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dikshita Agarwal X-Patchwork-Id: 850920 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 8D3E8212D8F; Thu, 12 Dec 2024 11:52:42 +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=1734004365; cv=none; b=LRaOtfc8MdQpxtphWUQfHrjB5KIvlNjTzOQWxOEN9ZxBgGfng2VAXhy5BpiWv8Cn2WoJv0USI0ZK3vD51LDhvUyo8A9ra5331D7d/UZ0gJh4Gidxkxm0ziHJ2wzijdi6Bn617gKX9FDByiSB8fWAsoYachJZYeh3BmcJEuX7y5o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734004365; c=relaxed/simple; bh=nTqF+p3EOGdiwqGekQoUvdiAzR7YDl05337Fy4MUPe4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=l9QS8ZdTF9cUPZac+XEEPR0hyo8mqoA3pVFL9wAb4WA7+X0muFs6kpySg/+2uH9K0GLR9fC11/tFHn05e1Cmdbms+aDngvMgDI7PYRvQ+HPn5dLROcOYUUZjxdbUjhXnaO+BSqUlxujylV3m7LyB27qt4CmKdY7y/Adc8f2W0O0= 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=IsNzmdZq; 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="IsNzmdZq" Received: from pps.filterd (m0279862.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 4BC7cSfU032708; Thu, 12 Dec 2024 11:52:30 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= B1ReXsSxO5i9NVTpNi/iAEkcIR48QzPs14+1I538u8Y=; b=IsNzmdZqQXOGNtR4 AEnLpAYGCCR2pbNHBO93+ex4l7xBI/k9tsnkNSzO8so7uH3D6m//7wYgpYLC/Tz4 Dsburv1spdrSY4oBtsjmNymVvPBaoiWOsVAQMsAP6PgLkHtUzXjZfhB7huww5yIk wtj1aHf1FP7Tm793LSoAOj5rME+6onAzrUNZlXqYdymIla4PCwwJDyMkWZ1JRWpb 2DHz/nbnfz1VlVovg1MaEh0EuziGRvRolUzBAQ0FqWfHoM0FDYpYKa+1pHONL1hg Vod/nTJwQWbpMGO2qEp4kQv80jAmB3aFTTHiMnuC/vMpSMGW71FsqktnvOuKHfC/ 3CMmrA== Received: from nalasppmta03.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 43f6tfc1je-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 12 Dec 2024 11:52:30 +0000 (GMT) Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA03.qualcomm.com (8.18.1.2/8.18.1.2) with ESMTPS id 4BCBqT5k020875 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 12 Dec 2024 11:52:29 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; Thu, 12 Dec 2024 03:52:23 -0800 From: Dikshita Agarwal Date: Thu, 12 Dec 2024 17:21:30 +0530 Subject: [PATCH v9 08/28] media: iris: implement power management Precedence: bulk X-Mailing-List: linux-media@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-ID: <20241212-qcom-video-iris-v9-8-e8c2c6bd4041@quicinc.com> References: <20241212-qcom-video-iris-v9-0-e8c2c6bd4041@quicinc.com> In-Reply-To: <20241212-qcom-video-iris-v9-0-e8c2c6bd4041@quicinc.com> To: Vikash Garodia , Abhinav Kumar , Mauro Carvalho Chehab , "Rob Herring" , Krzysztof Kozlowski , "Conor Dooley" , Philipp Zabel CC: Hans Verkuil , Sebastian Fricke , Bryan O'Donoghue , Dmitry Baryshkov , Neil Armstrong , Nicolas Dufresne , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Jianhua Lu , "Stefan Schmidt" , , , , , Dikshita Agarwal X-Mailer: b4 0.14.1 X-Developer-Signature: v=1; a=ed25519-sha256; t=1734004294; l=38677; i=quic_dikshita@quicinc.com; s=20240917; h=from:subject:message-id; bh=nTqF+p3EOGdiwqGekQoUvdiAzR7YDl05337Fy4MUPe4=; b=J3OLsHG1YP00cD5czxem0GBWIIUdLoPWbgm+nrj9MXAOqSCzVC45EirT4iwHIexnNarZUrEMN +T9iV069NRCBGwnoedvGZJZxXCAhYe8hScdIB8C8gD2ly4KONMjzWSg 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: IxS4yDo-Preg0tCGrDPQZpIvyCiHArq5 X-Proofpoint-ORIG-GUID: IxS4yDo-Preg0tCGrDPQZpIvyCiHArq5 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 mlxscore=0 suspectscore=0 mlxlogscore=999 malwarescore=0 spamscore=0 lowpriorityscore=0 impostorscore=0 adultscore=0 bulkscore=0 phishscore=0 priorityscore=1501 clxscore=1015 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2411120000 definitions=main-2412120085 Implement runtime power management for iris including platform specific power on/off sequence. Tested-by: Stefan Schmidt # x1e80100 (Dell Reviewed-by: Stefan Schmidt 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 | 243 ++++++++++++++++++++- drivers/media/platform/qcom/iris/iris_vpu_common.h | 11 + .../platform/qcom/iris/iris_vpu_register_defines.h | 17 ++ 25 files changed, 755 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/qcom/iris/Makefile b/drivers/media/platform/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 += 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 \ obj-$(CONFIG_VIDEO_QCOM_IRIS) += iris.o diff --git a/drivers/media/platform/qcom/iris/iris_core.c b/drivers/media/platform/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 reserved. */ +#include + #include "iris_core.h" #include "iris_firmware.h" #include "iris_state.h" @@ -10,11 +12,16 @@ 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 = IRIS_CORE_DEINIT; mutex_unlock(&core->lock); + + pm_runtime_put_sync(core->dev); } 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; - ret = iris_fw_load(core); + ret = iris_vpu_power_on(core); if (ret) goto error_queue_deinit; + ret = iris_fw_load(core); + if (ret) + goto error_power_off; + ret = iris_vpu_boot_firmware(core); if (ret) goto error_unload_fw; @@ -72,6 +83,8 @@ int iris_core_init(struct iris_core *core) 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/platform/qcom/iris/iris_core.h index c0f3c189d779..58aab78ab2c4 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__ #include +#include #include #include "iris_hfi_common.h" #include "iris_hfi_queue.h" #include "iris_platform_common.h" +#include "iris_resources.h" #include "iris_state.h" 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/media/platform/qcom/iris/iris_firmware.c index 3d14e596a471..7c493b4a75db 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.c +++ b/drivers/media/platform/qcom/iris/iris_firmware.c @@ -109,3 +109,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/media/platform/qcom/iris/iris_firmware.h index 266bdd92a124..e833ecd34887 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; 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); #endif diff --git a/drivers/media/platform/qcom/iris/iris_hfi_common.c b/drivers/media/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 reserved. */ +#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; mutex_lock(&core->lock); + pm_runtime_mark_last_busy(core->dev); iris_vpu_clear_interrupt(core); mutex_unlock(&core->lock); @@ -48,3 +52,61 @@ irqreturn_t iris_hfi_isr_handler(int irq, void *data) return IRQ_HANDLED; } + +int iris_hfi_pm_suspend(struct iris_core *core) +{ + int ret; + + ret = iris_vpu_prepare_pc(core); + if (ret) { + pm_runtime_mark_last_busy(core->dev); + ret = -EAGAIN; + goto error; + } + + ret = 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 = core->hfi_ops; + int ret; + + ret = iris_vpu_power_on(core); + if (ret) + goto error; + + ret = iris_set_hw_state(core, true); + if (ret) + goto err_power_off; + + ret = iris_vpu_boot_firmware(core); + if (ret) + goto err_suspend_hw; + + ret = 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/media/platform/qcom/iris/iris_hfi_common.h index b46a2f21102a..36673aafe1c9 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); }; struct iris_hfi_response_ops { @@ -53,6 +54,8 @@ struct iris_hfi_response_ops { }; 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); 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/drivers/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(struct iris_core *core) return ret; } +static int iris_hfi_gen1_sys_pc_prep(struct iris_core *core) +{ + struct hfi_sys_pc_prep_pkt pkt; + + pkt.hdr.size = sizeof(struct hfi_sys_pc_prep_pkt); + pkt.hdr.pkt_type = 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 = { .sys_init = iris_hfi_gen1_sys_init, .sys_image_version = iris_hfi_gen1_sys_image_version, .sys_interframe_powercollapse = iris_hfi_gen1_sys_interframe_powercollapse, + .sys_pc_prep = iris_hfi_gen1_sys_pc_prep, }; 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/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h index 8af824a42bcf..81685a284f23 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 #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 @@ -48,6 +49,10 @@ struct hfi_sys_get_property_pkt { u32 data; }; +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/drivers/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(struct iris_core *core) return ret; } +static int iris_hfi_gen2_sys_pc_prep(struct iris_core *core) +{ + struct iris_hfi_header *hdr; + int ret; + + hdr = kzalloc(SYS_NO_PAYLOAD_PKT_SIZE, GFP_KERNEL); + if (!hdr) + return -ENOMEM; + + iris_hfi_gen2_packet_sys_pc_prep(core, hdr); + ret = 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 = { .sys_init = iris_hfi_gen2_sys_init, .sys_image_version = iris_hfi_gen2_sys_image_version, .sys_interframe_powercollapse = iris_hfi_gen2_sys_interframe_powercollapse, + .sys_pc_prep = iris_hfi_gen2_sys_pc_prep, }; 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/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h index 2640caa7f9c0..e6a19ffc12fb 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 @@ #define HFI_CMD_BEGIN 0x01000000 #define HFI_CMD_INIT 0x01000001 +#define HFI_CMD_POWER_COLLAPSE 0x01000002 #define HFI_CMD_END 0x01FFFFFF #define HFI_PROP_BEGIN 0x03000000 diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.c b/drivers/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/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.h index 10dcb6e4c3d9..3b771b7516de 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 iris_hfi_header *hdr); void iris_hfi_gen2_packet_sys_interframe_powercollapse(struct iris_core *core, struct iris_hfi_header *hdr); +void iris_hfi_gen2_packet_sys_pc_prep(struct iris_core *core, struct iris_hfi_header *hdr); #endif diff --git a/drivers/media/platform/qcom/iris/iris_hfi_queue.c b/drivers/media/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 reserved. */ +#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; + ret = pm_runtime_resume_and_get(core->dev); + if (ret < 0) + goto exit; + mutex_lock(&core->lock); ret = iris_hfi_queue_cmd_write_locked(core, pkt, pkt_size); + if (ret) { + mutex_unlock(&core->lock); + goto exit; + } mutex_unlock(&core->lock); + pm_runtime_mark_last_busy(core->dev); + pm_runtime_put_autosuspend(core->dev); + + return 0; + +exit: + pm_runtime_put_sync(core->dev); + return ret; } diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h index adf639d1a109..69c0a8b3d12d 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; #define IRIS_PAS_ID 9 #define HW_RESPONSE_TIMEOUT_VALUE (1000) /* milliseconds */ +#define AUTOSUSPEND_DELAY_VALUE (HW_RESPONSE_TIMEOUT_VALUE + 500) /* milliseconds */ extern struct iris_platform_data sm8550_data; @@ -41,10 +42,22 @@ struct ubwc_config_data { u32 bank_spreading; }; +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; }; #endif diff --git a/drivers/media/platform/qcom/iris/iris_platform_sm8550.c b/drivers/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" #define VIDEO_ARCH_LX 1 +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[] = { { "cpu-cfg", 1000, 1000 }, { "video-mem", 1000, 15000000 }, @@ -47,6 +53,8 @@ struct iris_platform_data sm8550_data = { .get_instance = iris_hfi_gen2_get_instance, .init_hfi_command_ops = iris_hfi_gen2_command_ops_init, .init_hfi_response_ops = iris_hfi_gen2_response_ops_init, + .vpu_ops = &iris_vpu3_ops, + .set_preset_registers = iris_set_sm8550_preset_registers, .icc_tbl = sm8550_icc_table, .icc_tbl_size = ARRAY_SIZE(sm8550_icc_table), .clk_rst_tbl = sm8550_clk_reset_table, @@ -64,4 +72,5 @@ struct iris_platform_data sm8550_data = { .core_arch = VIDEO_ARCH_LX, .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, .ubwc_config = &ubwc_config_sm8550, + .num_vpp_pipe = 4, }; diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c index 02887b3dbe0e..e8ef258b4f2e 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 #include "iris_core.h" @@ -252,6 +253,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)); + pm_runtime_set_autosuspend_delay(core->dev, AUTOSUSPEND_DELAY_VALUE); + pm_runtime_use_autosuspend(core->dev); + ret = devm_pm_runtime_enable(core->dev); + if (ret) + goto err_vdev_unreg; + return 0; err_vdev_unreg: @@ -262,6 +269,51 @@ static int iris_probe(struct platform_device *pdev) return ret; } +static int __maybe_unused iris_pm_suspend(struct device *dev) +{ + struct iris_core *core; + int ret = 0; + + core = dev_get_drvdata(dev); + + mutex_lock(&core->lock); + if (core->state != IRIS_CORE_INIT) + goto exit; + + ret = iris_hfi_pm_suspend(core); + +exit: + mutex_unlock(&core->lock); + + return ret; +} + +static int __maybe_unused iris_pm_resume(struct device *dev) +{ + struct iris_core *core; + int ret = 0; + + core = dev_get_drvdata(dev); + + mutex_lock(&core->lock); + if (core->state != IRIS_CORE_INIT) + goto exit; + + ret = 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 = { + 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[] = { { .compatible = "qcom,sm8550-iris", @@ -277,6 +329,7 @@ static struct platform_driver qcom_iris_driver = { .driver = { .name = "qcom-iris", .of_match_table = iris_dt_match, + .pm = &iris_pm_ops, }, }; diff --git a/drivers/media/platform/qcom/iris/iris_resources.c b/drivers/media/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 reserved. + */ + +#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 = 0, bw_prev = 0; + const struct icc_info *icc_tbl; + int ret = 0, i; + + icc_tbl = core->iris_platform_data->icc_tbl; + + for (i = 0; i < core->icc_count; i++) { + if (!strcmp(core->icc_tbl[i].name, "video-mem")) { + bw_kbps = icc_bw; + bw_prev = core->power.icc_bw; + + bw_kbps = 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 = bw_kbps; + + core->power.icc_bw = 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 = 0; + + for (i = 0; i < core->icc_count; i++) { + core->icc_tbl[i].avg_bw = 0; + core->icc_tbl[i].peak_bw = 0; + } + + return icc_bulk_set_bw(core->icc_count, core->icc_tbl); +} + +int iris_enable_power_domains(struct iris_core *core, struct device *pd_dev) +{ + int ret; + + ret = dev_pm_opp_set_rate(core->dev, ULONG_MAX); + if (ret) + return ret; + + ret = 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_dev) +{ + int ret; + + ret = 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 platform_clk_type clk_type) +{ + const struct platform_clk_data *clk_tbl; + u32 clk_cnt, i, j; + + clk_tbl = core->iris_platform_data->clk_tbl; + clk_cnt = core->iris_platform_data->clk_tbl_size; + + for (i = 0; i < clk_cnt; i++) { + if (clk_tbl[i].clk_type == clk_type) { + for (j = 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_type clk_type) +{ + struct clk *clock; + + clock = 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 = 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/media/platform/qcom/iris/iris_resources.h new file mode 100644 index 000000000000..f723dfe5bd81 --- /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 reserved. + */ + +#ifndef __IRIS_RESOURCES_H__ +#define __IRIS_RESOURCES_H__ + +struct iris_core; + +int iris_enable_power_domains(struct iris_core *core, struct device *pd_dev); +int iris_disable_power_domains(struct iris_core *core, struct device *pd_dev); +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_type clk_type); + +#endif diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/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 reserved. */ +#include #include #include @@ -81,12 +82,19 @@ int iris_open(struct file *filp) struct iris_inst *inst; int ret; + ret = pm_runtime_resume_and_get(core->dev); + if (ret < 0) + return ret; + ret = iris_core_init(core); if (ret) { dev_err(core->dev, "core init failed\n"); + pm_runtime_put_sync(core->dev); return ret; } + pm_runtime_put_sync(core->dev); + inst = core->iris_platform_data->get_instance(); if (!inst) return -ENOMEM; diff --git a/drivers/media/platform/qcom/iris/iris_vpu2.c b/drivers/media/platform/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 reserved. + */ + +#include "iris_instance.h" +#include "iris_vpu_common.h" + +const struct vpu_ops iris_vpu2_ops = { + .power_off_hw = iris_vpu_power_off_hw, +}; diff --git a/drivers/media/platform/qcom/iris/iris_vpu3.c b/drivers/media/platform/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 reserved. + */ + +#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 = readl(core->reg_base + WRAPPER_CORE_POWER_STATUS); + pwr_status = value & BIT(1); + + return pwr_status ? false : true; +} + +static void iris_vpu3_power_off_hardware(struct iris_core *core) +{ + u32 reg_val = 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 = readl(core->reg_base + WRAPPER_CORE_CLOCK_CONFIG); + if (value) + writel(CORE_CLK_RUN, core->reg_base + WRAPPER_CORE_CLOCK_CONFIG); + + for (i = 0; i < core->iris_platform_data->num_vpp_pipe; i++) { + ret = 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_REQ); + + ret = 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 = 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_SYNC_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 = { + .power_off_hw = iris_vpu3_power_off_hardware, +}; diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.c b/drivers/media/platform/qcom/iris/iris_vpu_common.c index 34817573f61b..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 @@ */ #include +#include +#include #include "iris_core.h" #include "iris_vpu_common.h" +#include "iris_vpu_register_defines.h" -#define CPU_BASE_OFFS 0x000A0000 +#define WRAPPER_TZ_BASE_OFFS 0x000C0000 +#define AON_BASE_OFFS 0x000E0000 -#define CPU_CS_BASE_OFFS (CPU_BASE_OFFS) #define CPU_IC_BASE_OFFS (CPU_BASE_OFFS) #define CPU_CS_A2HSOFTINTCLR (CPU_CS_BASE_OFFS + 0x1C) @@ -21,6 +24,7 @@ #define CTRL_INIT_IDLE_MSG_BMSK 0x40000000 #define CTRL_ERROR_STATUS__M 0xfe +#define CTRL_STATUS_PC_READY 0x100 #define QTBL_INFO (CPU_CS_BASE_OFFS + 0x50) #define QTBL_ENABLE BIT(0) @@ -35,15 +39,48 @@ #define HOST2XTENSA_INTR_ENABLE BIT(0) #define CPU_CS_X2RPMH (CPU_CS_BASE_OFFS + 0x168) +#define MSK_SIGNAL_FROM_TENSILICA BIT(0) +#define MSK_CORE_POWER_ON BIT(1) #define CPU_IC_SOFTINT (CPU_IC_BASE_OFFS + 0x150) #define CPU_IC_SOFTINT_H2A_SHFT 0x0 -#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) +#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 = readl(core->reg_base + WRAPPER_INTR_MASK); + mask_val &= ~(WRAPPER_INTR_MASK_A2HWD_BMSK | + WRAPPER_INTR_MASK_A2HCPU_BMSK); + writel(mask_val, core->reg_base + WRAPPER_INTR_MASK); +} + static void iris_vpu_setup_ucregion_memory_map(struct iris_core *core) { u32 queue_size, value; @@ -130,3 +167,203 @@ int iris_vpu_watchdog(struct iris_core *core, u32 intr_status) return 0; } + +int iris_vpu_prepare_pc(struct iris_core *core) +{ + u32 wfi_status, idle_status, pc_ready; + u32 ctrl_status, val = 0; + int ret; + + ctrl_status = readl(core->reg_base + CTRL_STATUS); + pc_ready = ctrl_status & CTRL_STATUS_PC_READY; + idle_status = ctrl_status & BIT(30); + if (pc_ready) + return 0; + + wfi_status = readl(core->reg_base + WRAPPER_TZ_CPU_STATUS); + wfi_status &= BIT(0); + if (!wfi_status || !idle_status) + goto skip_power_off; + + ret = core->hfi_ops->sys_pc_prep(core); + if (ret) + goto skip_power_off; + + ret = readl_poll_timeout(core->reg_base + CTRL_STATUS, val, + val & CTRL_STATUS_PC_READY, 250, 2500); + if (ret) + goto skip_power_off; + + ret = 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 = readl(core->reg_base + CTRL_STATUS); + wfi_status = readl(core->reg_base + WRAPPER_TZ_CPU_STATUS); + wfi_status &= BIT(0); + dev_err(core->dev, "skip power collapse, wfi=%#x, idle=%#x, pcr=%#x, ctrl=%#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 = 0; + int ret; + + writel(MSK_SIGNAL_FROM_TENSILICA | MSK_CORE_POWER_ON, core->reg_base + CPU_CS_X2RPMH); + + writel(REQ_POWER_DOWN_PREP, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); + + ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_LPI_STATUS, + val, val & BIT(0), 200, 2000); + if (ret) + goto disable_power; + + writel(REQ_POWER_DOWN_PREP, core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_CONTROL); + + ret = readl_poll_timeout(core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_STATUS, + val, val & BIT(0), 200, 2000); + if (ret) + goto disable_power; + + writel(0x0, core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_CONTROL); + + ret = readl_poll_timeout(core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_STATUS, + val, val == 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_POWER_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_POWER_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 = core->iris_platform_data->clk_rst_tbl_size; + int ret; + + ret = iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); + if (ret) + return ret; + + ret = reset_control_bulk_reset(rst_tbl_size, core->resets); + if (ret) + goto err_disable_power; + + ret = iris_prepare_enable_clock(core, IRIS_AXI_CLK); + if (ret) + goto err_disable_power; + + ret = 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_POWER_DOMAIN]); + + return ret; +} + +static int iris_vpu_power_on_hw(struct iris_core *core) +{ + int ret; + + ret = iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]); + if (ret) + return ret; + + ret = iris_prepare_enable_clock(core, IRIS_HW_CLK); + if (ret) + goto err_disable_power; + + ret = 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_POWER_DOMAIN]); + + return ret; +} + +int iris_vpu_power_on(struct iris_core *core) +{ + u32 freq; + int ret; + + ret = iris_set_icc_bw(core, INT_MAX); + if (ret) + goto err; + + ret = iris_vpu_power_on_controller(core); + if (ret) + goto err_unvote_icc; + + ret = iris_vpu_power_on_hw(core); + if (ret) + goto err_power_off_ctrl; + + freq = 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 = 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/media/platform/qcom/iris/iris_vpu_common.h index c38c055d3d14..d3efa7c0ce9a 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 @@ struct iris_core; +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); #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..fe8a39e5e5a3 --- /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 reserved. + */ + +#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