platform: dce: Add suspend resume hooks

Add suspend resume hooks function and handling of sc7 events.

Bug 3583331
Bug 3826630

Signed-off-by: Mahesh Kumar <mahkumar@nvidia.com>
Change-Id: I920b02ad46a76330febe666fe17e8d328f744b1d
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2834856
Reviewed-by: Arun Swain <arswain@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2824218
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
Reviewed-by: svc-mobile-cert <svc-mobile-cert@nvidia.com>
Reviewed-by: svc_kernel_abi <svc_kernel_abi@nvidia.com>
This commit is contained in:
Mahesh Kumar
2022-05-19 15:01:13 +00:00
committed by Laxman Dewangan
parent 31b6d913ab
commit 75bfcf326d
10 changed files with 373 additions and 18 deletions

View File

@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# #
# Display Controller Engine code. # Display Controller Engine code.
# #
@@ -34,6 +34,7 @@ tegra-dce-$(CONFIG_TEGRA_DCE) += \
dce-ipc-signal.o \ dce-ipc-signal.o \
dce-client-ipc.o \ dce-client-ipc.o \
dce-module.o \ dce-module.o \
dce-pm.o \
dce-util-common.o dce-util-common.o
ifeq ($(CONFIG_DEBUG_FS),y) ifeq ($(CONFIG_DEBUG_FS),y)

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2022, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2019-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -471,6 +471,79 @@ out:
return ret; return ret;
} }
/**
* dce_admin_send_prepare_sc7 - Sends DCE_ADMIN_CMD_PREPARE_SC7 cmd.
*
* @d - Pointer to tegra_dce struct.
* @msg - Pointer to dce_ipc_msg struct.
*
* Return - 0 if successful
*/
int dce_admin_send_prepare_sc7(struct tegra_dce *d,
struct dce_ipc_message *msg)
{
int ret = -1;
struct dce_admin_ipc_cmd *req_msg;
struct dce_admin_ipc_resp *resp_msg;
if (!msg || !msg->tx.data || !msg->rx.data)
goto out;
req_msg = (struct dce_admin_ipc_cmd *)(msg->tx.data);
resp_msg = (struct dce_admin_ipc_resp *) (msg->rx.data);
req_msg->cmd = (uint32_t)DCE_ADMIN_CMD_PREPARE_SC7;
ret = dce_admin_send_msg(d, msg);
if (ret) {
dce_err(d, "Error sending prepare sc7 command [%d]", ret);
goto out;
}
out:
return ret;
}
/**
* dce_admin_send_enter_sc7 - Sends DCE_ADMIN_CMD_ENTER_SC7 cmd.
*
* @d - Pointer to tegra_dce struct.
* @msg - Pointer to dce_ipc_msg struct.
*
* Return - 0 if successful
*/
int dce_admin_send_enter_sc7(struct tegra_dce *d,
struct dce_ipc_message *msg)
{
int ret = -1;
struct dce_admin_ipc_cmd *req_msg;
struct dce_admin_ipc_resp *resp_msg;
if (!msg || !msg->tx.data || !msg->rx.data)
goto out;
req_msg = (struct dce_admin_ipc_cmd *)(msg->tx.data);
resp_msg = (struct dce_admin_ipc_resp *) (msg->rx.data);
req_msg->cmd = (uint32_t)DCE_ADMIN_CMD_ENTER_SC7;
ret = dce_ipc_send_message(d, DCE_IPC_CHANNEL_TYPE_ADMIN, msg->tx.data, msg->tx.size);
if (ret) {
dce_err(d, "Error sending enter sc7 command [%d]", ret);
goto out;
}
/* Wait for SC7 Enter done */
ret = dce_wait_interruptible(d, DCE_WAIT_SC7_ENTER);
if (ret) {
dce_err(d, "SC7 Enter wait was interrupted with err:%d", ret);
goto out;
}
out:
return ret;
}
static int dce_admin_setup_clients_ipc(struct tegra_dce *d, static int dce_admin_setup_clients_ipc(struct tegra_dce *d,
struct dce_ipc_message *msg) struct dce_ipc_message *msg)
{ {

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2022, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2019-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -151,7 +151,7 @@ int dce_handle_boot_complete_received_event(struct tegra_dce *d, void *params)
* *
* Return : 0 if successful else error code * Return : 0 if successful else error code
*/ */
static int int
dce_start_boot_flow(struct tegra_dce *d) dce_start_boot_flow(struct tegra_dce *d)
{ {
int ret = 0; int ret = 0;
@@ -241,8 +241,12 @@ void dce_handle_irq_status(struct tegra_dce *d, u32 status)
NULL); NULL);
} }
if (status & DCE_IRQ_SC7_ENTERED) if (status & DCE_IRQ_SC7_ENTERED) {
dce_info(d, "DCE can be safely powered-off now"); dce_info(d, "DCE can be safely powered-off now");
(void)dce_fsm_post_event(d,
EVENT_ID_DCE_SC7_ENTERED_RECEIVED,
NULL);
}
if (status & DCE_IRQ_LOG_READY) { if (status & DCE_IRQ_LOG_READY) {
dce_info(d, "DCE trace log buffers available"); dce_info(d, "DCE trace log buffers available");

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -53,11 +53,15 @@ static struct dce_event_process_struct event_process_table[] = {
}, },
{ {
.event = EVENT_ID_DCE_SC7_ENTER_REQUESTED, .event = EVENT_ID_DCE_SC7_ENTER_REQUESTED,
.fsm_event_handle = dce_handle_event_stub, .fsm_event_handle = dce_pm_handle_sc7_enter_requested_event,
}, },
{ {
.event = EVENT_ID_DCE_SC7_ENTERED_RECEIVED, .event = EVENT_ID_DCE_SC7_ENTERED_RECEIVED,
.fsm_event_handle = dce_handle_event_stub, .fsm_event_handle = dce_pm_handle_sc7_enter_received_event,
},
{
.event = EVENT_ID_DCE_SC7_EXIT_RECEIVED,
.fsm_event_handle = dce_pm_handle_sc7_exit_received_event,
}, },
{ {
.event = EVENT_ID_DCE_LOG_REQUESTED, .event = EVENT_ID_DCE_LOG_REQUESTED,
@@ -178,6 +182,11 @@ dce_fsm_set_state(struct tegra_dce *d,
fsm->requested_ipcs &= ~DCE_BIT(DCE_WAIT_SC7_ENTER); fsm->requested_ipcs &= ~DCE_BIT(DCE_WAIT_SC7_ENTER);
break; break;
case EVENT_ID_DCE_SC7_EXIT_RECEIVED:
fsm->c_state = STATE_DCE_FSM_IDLE;
fsm->requested_ipcs = 0;
break;
case EVENT_ID_DCE_LOG_REQUESTED: case EVENT_ID_DCE_LOG_REQUESTED:
fsm->c_state = STATE_DCE_LOG_READY_WFI; fsm->c_state = STATE_DCE_LOG_READY_WFI;
fsm->requested_ipcs |= DCE_BIT(DCE_WAIT_LOG); fsm->requested_ipcs |= DCE_BIT(DCE_WAIT_LOG);
@@ -355,11 +364,16 @@ dce_fsm_validate_event(struct tegra_dce *d,
} }
break; break;
case STATE_DCE_SC7_ENTERED: case STATE_DCE_SC7_ENTERED:
// switch (event) {
// STATE_DCE_SC7_ENTERED is short lived state for now case EVENT_ID_DCE_SC7_EXIT_RECEIVED:
// FSM can expect only EVENT_ID_DCE_FSM_START event here ret = 0;
// break;
dce_err(d, "Event received while in STATE_DCE_SC7_ENTERED state"); default:
dce_err(d, "Invalid event received [%d] state:[%d]\n",
event, curr_state);
ret = -EINVAL;
break;
}
break; break;
default: default:
dce_err(d, "Invalid state:[%d] event received [%d]\n", curr_state, dce_err(d, "Invalid state:[%d] event received [%d]\n", curr_state,

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2023, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2019-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -59,6 +59,19 @@ static inline struct tegra_dce *dce_get_pdata_dce(struct platform_device *pdev)
return (&((struct dce_device *)dev_get_drvdata(&pdev->dev))->d); return (&((struct dce_device *)dev_get_drvdata(&pdev->dev))->d);
} }
/**
* dce_get_tegra_dce_from_dev - inline function to get the tegra_dce pointer
* from devicve struct.
*
* @pdev : Pointer to the device data structure.
*
* Return : Pointer pointing to tegra_dce data structure.
*/
static inline struct tegra_dce *dce_get_tegra_dce_from_dev(struct device *dev)
{
return (&((struct dce_device *)dev_get_drvdata(dev))->d);
}
/** /**
* dce_init_dev_data - Function to initialize the dce device data structure. * dce_init_dev_data - Function to initialize the dce device data structure.
* *
@@ -273,11 +286,35 @@ static int tegra_dce_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM
static int dce_pm_suspend(struct device *dev)
{
struct tegra_dce *d = dce_get_tegra_dce_from_dev(dev);
return dce_pm_enter_sc7(d);
}
static int dce_pm_resume(struct device *dev)
{
struct tegra_dce *d = dce_get_tegra_dce_from_dev(dev);
return dce_pm_exit_sc7(d);
}
const struct dev_pm_ops dce_pm_ops = {
.suspend = dce_pm_suspend,
.resume = dce_pm_resume,
};
#endif
static struct platform_driver tegra_dce_driver = { static struct platform_driver tegra_dce_driver = {
.driver = { .driver = {
.name = "tegra-dce", .name = "tegra-dce",
.of_match_table = .of_match_table =
of_match_ptr(tegra_dce_of_match), of_match_ptr(tegra_dce_of_match),
#ifdef CONFIG_PM
.pm = &dce_pm_ops,
#endif
}, },
.probe = tegra_dce_probe, .probe = tegra_dce_probe,
.remove = tegra_dce_remove, .remove = tegra_dce_remove,

View File

@@ -0,0 +1,175 @@
/*
* Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <dce.h>
#define CCPLEX_HSP_IE 1U /* TODO : Have an api to read from platform data */
static void dce_pm_save_state(struct tegra_dce *d)
{
d->sc7_state.hsp_ie = dce_hsp_ie_read(d, CCPLEX_HSP_IE);
}
static void dce_pm_restore_state(struct tegra_dce *d)
{
uint32_t val = d->sc7_state.hsp_ie;
dce_hsp_ie_write(d, val, CCPLEX_HSP_IE);
}
/**
* dce_resume_work_fn : execute resume and bootstrap flow
*
* @d : Pointer to tegra_dce struct.
*
* Return : void
*/
void dce_resume_work_fn(struct tegra_dce *d)
{
int ret = 0;
if (d == NULL) {
dce_err(d, "tegra_dce struct is NULL");
return;
}
ret = dce_fsm_post_event(d, EVENT_ID_DCE_BOOT_COMPLETE_REQUESTED, NULL);
if (ret) {
dce_err(d, "Error while posting DCE_BOOT_COMPLETE_REQUESTED event");
return;
}
ret = dce_start_boot_flow(d);
if (ret) {
dce_err(d, "DCE bootstrapping failed\n");
return;
}
}
/**
* dce_handle_sc7_enter_requested_event - callback handler function for event
* EVENT_ID_DCE_SC7_ENTER_REQUESTED
*
* @d : Pointer to tegra_dce struct.
* @params : callback params
*
* Return : 0 if successful else error code
*/
int dce_pm_handle_sc7_enter_requested_event(struct tegra_dce *d, void *params)
{
int ret = 0;
struct dce_ipc_message *msg = NULL;
msg = dce_admin_allocate_message(d);
if (!msg) {
dce_err(d, "IPC msg allocation failed");
goto out;
}
ret = dce_admin_send_enter_sc7(d, msg);
if (ret) {
dce_err(d, "Enter SC7 failed [%d]", ret);
goto out;
}
out:
dce_admin_free_message(d, msg);
return ret;
}
/**
* dce_handle_sc7_enter_received_event - callback handler function for event
* EVENT_ID_DCE_SC7_ENTER_RECEIVED
*
* @d : Pointer to tegra_dce struct.
* @params : callback params
*
* Return : 0 if successful else error code
*/
int dce_pm_handle_sc7_enter_received_event(struct tegra_dce *d, void *params)
{
dce_wakeup_interruptible(d, DCE_WAIT_SC7_ENTER);
return 0;
}
/**
* dce_handle_sc7_exit_received_event - callback handler function for event
* EVENT_ID_DCE_SC7_EXIT_RECEIVED
*
* @d : Pointer to tegra_dce struct.
* @params : callback params
*
* Return : 0 if successful else error code
*/
int dce_pm_handle_sc7_exit_received_event(struct tegra_dce *d, void *params)
{
dce_schedule_work(&d->dce_resume_work);
return 0;
}
int dce_pm_enter_sc7(struct tegra_dce *d)
{
int ret = 0;
struct dce_ipc_message *msg = NULL;
/*
* If Bootstrap is not yet done. Nothing to do during SC7 Enter
* Return success immediately.
*/
if (!dce_is_bootstrap_done(d)) {
dce_debug(d, "Bootstrap not done, Succeed SC7 enter\n");
goto out;
}
msg = dce_admin_allocate_message(d);
if (!msg) {
dce_err(d, "IPC msg allocation failed");
ret = -1;
goto out;
}
dce_pm_save_state(d);
ret = dce_admin_send_prepare_sc7(d, msg);
if (ret) {
dce_err(d, "Prepare SC7 failed [%d]", ret);
ret = -1;
goto out;
}
ret = dce_fsm_post_event(d, EVENT_ID_DCE_SC7_ENTER_REQUESTED, NULL);
if (ret) {
dce_err(d, "Error while posting SC7_ENTER event [%d]", ret);
ret = -1;
goto out;
}
out:
dce_admin_free_message(d, msg);
return ret;
}
int dce_pm_exit_sc7(struct tegra_dce *d)
{
int ret = 0;
dce_pm_restore_state(d);
ret = dce_fsm_post_event(d, EVENT_ID_DCE_SC7_EXIT_RECEIVED, NULL);
if (ret) {
dce_err(d, "Error while posting SC7_EXIT event [%d]", ret);
goto out;
}
out:
return ret;
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * Copyright (c) 2019-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -85,7 +85,13 @@ int dce_work_cond_sw_resource_init(struct tegra_dce *d)
ret = dce_init_work(d, &d->dce_bootstrap_work, dce_bootstrap_work_fn); ret = dce_init_work(d, &d->dce_bootstrap_work, dce_bootstrap_work_fn);
if (ret) { if (ret) {
dce_err(d, "fsm_start work init failed"); dce_err(d, "Bootstrap work init failed");
goto exit;
}
ret = dce_init_work(d, &d->dce_resume_work, dce_resume_work_fn);
if (ret) {
dce_err(d, "resume work init failed");
goto exit; goto exit;
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -32,6 +32,7 @@ enum dce_fsm_event_id_type {
EVENT_ID_DCE_ADMIN_IPC_MSG_RECEIVED, EVENT_ID_DCE_ADMIN_IPC_MSG_RECEIVED,
EVENT_ID_DCE_SC7_ENTER_REQUESTED, EVENT_ID_DCE_SC7_ENTER_REQUESTED,
EVENT_ID_DCE_SC7_ENTERED_RECEIVED, EVENT_ID_DCE_SC7_ENTERED_RECEIVED,
EVENT_ID_DCE_SC7_EXIT_RECEIVED,
EVENT_ID_DCE_LOG_REQUESTED, EVENT_ID_DCE_LOG_REQUESTED,
EVENT_ID_DCE_LOG_READY_RECEIVED, EVENT_ID_DCE_LOG_READY_RECEIVED,
EVENT_ID_DCE_ABORT_RECEIVED, EVENT_ID_DCE_ABORT_RECEIVED,

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#ifndef DCE_PM_H
#define DCE_PM_H
#include <dce.h>
struct dce_sc7_state {
uint32_t hsp_ie;
};
int dce_pm_enter_sc7(struct tegra_dce *d);
int dce_pm_exit_sc7(struct tegra_dce *d);
void dce_resume_work_fn(struct tegra_dce *d);
int dce_pm_handle_sc7_enter_requested_event(struct tegra_dce *d, void *params);
int dce_pm_handle_sc7_enter_received_event(struct tegra_dce *d, void *params);
int dce_pm_handle_sc7_exit_received_event(struct tegra_dce *d, void *params);
#endif

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2022, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2019-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -25,6 +25,7 @@
#include <dce-thread.h> #include <dce-thread.h>
#include <dce-worker.h> #include <dce-worker.h>
#include <dce-fsm.h> #include <dce-fsm.h>
#include <dce-pm.h>
#include <dce-mailbox.h> #include <dce-mailbox.h>
#include <dce-client-ipc-internal.h> #include <dce-client-ipc-internal.h>
#include <dce-workqueue.h> #include <dce-workqueue.h>
@@ -148,6 +149,14 @@ struct tegra_dce {
* dce_bootstrap_work : dce work to be executed to start FSM flow * dce_bootstrap_work : dce work to be executed to start FSM flow
*/ */
struct dce_work_struct dce_bootstrap_work; struct dce_work_struct dce_bootstrap_work;
/**
* dce_resume_work : dce work to executed dce resume flow
*/
struct dce_work_struct dce_resume_work;
/**
* dce_sc7_state : structure to save/restore state during sc7 enter/exit
*/
struct dce_sc7_state sc7_state;
/** /**
* dce_wait_info - Data structure to manage wait for different event types * dce_wait_info - Data structure to manage wait for different event types
*/ */
@@ -377,6 +386,7 @@ const char *dce_get_fw_name(struct tegra_dce *d);
int dce_driver_init(struct tegra_dce *d); int dce_driver_init(struct tegra_dce *d);
void dce_driver_deinit(struct tegra_dce *d); void dce_driver_deinit(struct tegra_dce *d);
int dce_start_boot_flow(struct tegra_dce *d);
void dce_bootstrap_work_fn(struct tegra_dce *d); void dce_bootstrap_work_fn(struct tegra_dce *d);
int dce_start_bootstrap_flow(struct tegra_dce *d); int dce_start_bootstrap_flow(struct tegra_dce *d);
int dce_boot_interface_init(struct tegra_dce *d); int dce_boot_interface_init(struct tegra_dce *d);
@@ -402,6 +412,10 @@ int dce_admin_send_cmd_echo(struct tegra_dce *d,
struct dce_ipc_message *msg); struct dce_ipc_message *msg);
int dce_admin_send_cmd_ext_test(struct tegra_dce *d, int dce_admin_send_cmd_ext_test(struct tegra_dce *d,
struct dce_ipc_message *msg); struct dce_ipc_message *msg);
int dce_admin_send_prepare_sc7(struct tegra_dce *d,
struct dce_ipc_message *msg);
int dce_admin_send_enter_sc7(struct tegra_dce *d,
struct dce_ipc_message *msg);
int dce_admin_handle_ipc_requested_event(struct tegra_dce *d, void *params); int dce_admin_handle_ipc_requested_event(struct tegra_dce *d, void *params);
int dce_admin_handle_ipc_received_event(struct tegra_dce *d, void *params); int dce_admin_handle_ipc_received_event(struct tegra_dce *d, void *params);
int dce_admin_ipc_wait(struct tegra_dce *d, u32 w_type); int dce_admin_ipc_wait(struct tegra_dce *d, u32 w_type);