mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 09:11:26 +03:00
Merge "dce-kmd: Merge the dce-kmd driver from kernel/nvidia to kernel/nvidia-oot" into dev-main
This commit is contained in:
46
drivers/platform/tegra/dce/Makefile
Normal file
46
drivers/platform/tegra/dce/Makefile
Normal file
@@ -0,0 +1,46 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
#
|
||||
# Display Controller Engine code.
|
||||
#
|
||||
GCOV_PROFILE := y
|
||||
|
||||
ccflags-y += -I$(srctree.nvidia)/drivers/platform/tegra/dce/include
|
||||
ccflags-y += -Wno-multichar
|
||||
ccflags-y += -Werror
|
||||
ccflags-y += -Wno-error=cpp
|
||||
ifeq ($(VERSION),4)
|
||||
ccflags-y += -Wextra -Wno-unused-parameter -Wno-missing-field-initializers
|
||||
endif
|
||||
|
||||
# Set config when build as OOT module.
|
||||
ifeq ($(CONFIG_TEGRA_OOT_MODULE),m)
|
||||
CONFIG_TEGRA_DCE := m
|
||||
ccflags-y += -I$(srctree.nvidia)/include
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_TEGRA_DCE) += tegra-dce.o
|
||||
tegra-dce-$(CONFIG_TEGRA_DCE) += \
|
||||
dce-ast.o \
|
||||
dce-reset.o \
|
||||
dce-hsp-smb.o \
|
||||
dce-hsp-ss.o \
|
||||
dce-worker.o \
|
||||
dce-fsm.o \
|
||||
dce-init-deinit.o \
|
||||
dce-mailbox.o \
|
||||
dce-bootstrap.o \
|
||||
dce-admin.o \
|
||||
dce-ipc.o \
|
||||
dce-ipc-signal.o \
|
||||
dce-client-ipc.o \
|
||||
dce-module.o \
|
||||
dce-pm.o \
|
||||
dce-util-common.o
|
||||
|
||||
ifeq ($(CONFIG_DEBUG_FS),y)
|
||||
tegra-dce-$(CONFIG_TEGRA_DCE) += \
|
||||
dce-debug.o \
|
||||
dce-admin-debug.o \
|
||||
dce-debug-perf.o
|
||||
endif
|
||||
164
drivers/platform/tegra/dce/dce-admin-debug.c
Normal file
164
drivers/platform/tegra/dce/dce-admin-debug.c
Normal file
@@ -0,0 +1,164 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 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>
|
||||
#include <dce-mailbox.h>
|
||||
#include <dce-util-common.h>
|
||||
#include <dce-client-ipc-internal.h>
|
||||
#include <interface/dce-core-interface-errors.h>
|
||||
#include <interface/dce-interface.h>
|
||||
#include <interface/dce-admin-cmds.h>
|
||||
|
||||
/**
|
||||
* dce_admin_send_cmd_set_perf_stat - Start/stop DCE perf data collection.
|
||||
*
|
||||
* @d - Pointer to tegra_dce struct.
|
||||
* @msg - Pointer to dce_ipc_msg struct.
|
||||
* @start_perf - Bool to indicate start/stop of perf data collection
|
||||
*
|
||||
* Return - 0 if successful
|
||||
*/
|
||||
int dce_admin_send_cmd_set_perf_stat(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg,
|
||||
bool start_perf)
|
||||
{
|
||||
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;
|
||||
|
||||
/* return if dce bootstrap not completed */
|
||||
if (!dce_is_bootstrap_done(d)) {
|
||||
dce_err(d, "Admin Bootstrap not yet done");
|
||||
goto out;
|
||||
}
|
||||
|
||||
req_msg = (struct dce_admin_ipc_cmd *)(msg->tx.data);
|
||||
resp_msg = (struct dce_admin_ipc_resp *) (msg->rx.data);
|
||||
|
||||
if (start_perf == true)
|
||||
req_msg->cmd = (uint32_t)DCE_ADMIN_CMD_PERF_START;
|
||||
else
|
||||
req_msg->cmd = (uint32_t)DCE_ADMIN_CMD_PERF_STOP;
|
||||
|
||||
ret = dce_admin_send_msg(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "Error sending set perf msg : [%d]", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* dce_admin_send_cmd_get_perf_stat - Get DCE perf data.
|
||||
*
|
||||
* @d - Pointer to tegra_dce struct.
|
||||
* @msg - Pointer to dce_ipc_msg struct.
|
||||
*
|
||||
* Return - 0 if successful
|
||||
*/
|
||||
int dce_admin_send_cmd_get_perf_stat(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;
|
||||
|
||||
/* return if dce bootstrap not completed */
|
||||
if (!dce_is_bootstrap_done(d)) {
|
||||
dce_err(d, "Admin Bootstrap not yet done");
|
||||
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_PERF_RESULTS;
|
||||
|
||||
ret = dce_admin_send_msg(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "Error sending get perf msg : [%d]", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dce_admin_send_cmd_get_perf_events(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;
|
||||
|
||||
/* return if dce bootstrap not completed */
|
||||
if (!dce_is_bootstrap_done(d)) {
|
||||
dce_err(d, "Admin Bootstrap not yet done");
|
||||
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_PERF_GET_EVENTS;
|
||||
|
||||
ret = dce_admin_send_msg(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "Error sending get perf events msg : [%d]", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dce_admin_send_cmd_clear_perf_events(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg)
|
||||
{
|
||||
int ret = -1;
|
||||
struct dce_admin_ipc_cmd *req_msg;
|
||||
|
||||
if (!msg || !msg->tx.data || !msg->rx.data)
|
||||
goto out;
|
||||
|
||||
/* return if dce bootstrap not completed */
|
||||
if (!dce_is_bootstrap_done(d)) {
|
||||
dce_err(d, "Admin Bootstrap not yet done");
|
||||
goto out;
|
||||
}
|
||||
|
||||
req_msg = (struct dce_admin_ipc_cmd *)(msg->tx.data);
|
||||
|
||||
req_msg->cmd = (uint32_t)DCE_ADMIN_CMD_PERF_CLEAR_EVENTS;
|
||||
|
||||
ret = dce_admin_send_msg(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "Error sending clear perf events msg : [%d]", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
670
drivers/platform/tegra/dce/dce-admin.c
Normal file
670
drivers/platform/tegra/dce/dce-admin.c
Normal file
@@ -0,0 +1,670 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2019-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>
|
||||
#include <dce-mailbox.h>
|
||||
#include <dce-util-common.h>
|
||||
#include <dce-client-ipc-internal.h>
|
||||
#include <interface/dce-core-interface-errors.h>
|
||||
#include <interface/dce-interface.h>
|
||||
#include <interface/dce-admin-cmds.h>
|
||||
|
||||
/**
|
||||
* dce_admin_ipc_wait - Waits for message from DCE.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @w_type : Requested wait type.
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
int dce_admin_ipc_wait(struct tegra_dce *d, u32 w_type)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = dce_wait_interruptible(d, DCE_WAIT_ADMIN_IPC);
|
||||
if (ret) {
|
||||
/**
|
||||
* TODO: Add error handling for abort and retry
|
||||
*/
|
||||
dce_err(d, "Admin IPC wait was interrupted with err:%d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_admin_wakeup_ipc - wakeup process, waiting for Admin RPC
|
||||
*
|
||||
* @d : Pointer to tegra_de struct.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dce_admin_wakeup_ipc(struct tegra_dce *d)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = dce_fsm_post_event(d, EVENT_ID_DCE_ADMIN_IPC_MSG_RECEIVED, NULL);
|
||||
if (ret)
|
||||
dce_err(d, "Error while posting ADMIN_IPC_MSG_RECEIVED event");
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_admin_ipc_handle_signal - Isr for the CCPLEX<->DCE admin interface
|
||||
*
|
||||
* @d : Pointer to tegra_de struct.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
void dce_admin_ipc_handle_signal(struct tegra_dce *d, u32 ch_type)
|
||||
{
|
||||
bool wakeup_needed = false;
|
||||
|
||||
if (!dce_ipc_channel_is_synced(d, ch_type)) {
|
||||
/**
|
||||
* The ivc channel is not ready yet. Exit
|
||||
* and wait for another signal from target.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Channel already in sync with remote. Check if data
|
||||
* is available to read.
|
||||
*/
|
||||
wakeup_needed = dce_ipc_is_data_available(d, ch_type);
|
||||
|
||||
if (!wakeup_needed) {
|
||||
dce_info(d, "Spurious signal on channel: [%d]. Ignored...",
|
||||
ch_type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ch_type == DCE_IPC_CH_KMD_TYPE_ADMIN) {
|
||||
dce_admin_wakeup_ipc(d);
|
||||
} else {
|
||||
dce_client_ipc_wakeup(d, ch_type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_admin_ivc_channel_reset - Resets the admin ivc channel
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : Void.
|
||||
*/
|
||||
void dce_admin_ivc_channel_reset(struct tegra_dce *d)
|
||||
{
|
||||
dce_ipc_channel_reset(d, DCE_IPC_CH_KMD_TYPE_ADMIN);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_admin_channel_deinit - Cleans up the channel resources.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dce_admin_channel_deinit(struct tegra_dce *d)
|
||||
{
|
||||
u32 loop_cnt;
|
||||
|
||||
for (loop_cnt = 0; loop_cnt < DCE_IPC_CH_KMD_TYPE_MAX; loop_cnt++)
|
||||
dce_ipc_channel_deinit(d, loop_cnt);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* dce_admin_channel_init - Initializes the admin ivc interface
|
||||
*
|
||||
* @d : Pointer to tegra_dce.
|
||||
*
|
||||
* Return : 0 if successful.
|
||||
*/
|
||||
static int dce_admin_channel_init(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 loop_cnt;
|
||||
|
||||
for (loop_cnt = 0; loop_cnt < DCE_IPC_CH_KMD_TYPE_MAX; loop_cnt++) {
|
||||
ret = dce_ipc_channel_init(d, loop_cnt);
|
||||
if (ret) {
|
||||
dce_err(d, "Channel init failed for type : [%d]",
|
||||
loop_cnt);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (ret)
|
||||
dce_admin_channel_deinit(d);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_admin_init - Sets up resources managed by admin.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
int dce_admin_init(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
d->boot_status |= DCE_EARLY_INIT_START;
|
||||
ret = dce_ipc_allocate_region(d);
|
||||
if (ret) {
|
||||
dce_err(d, "IPC region allocation failed");
|
||||
goto err_ipc_reg_alloc;
|
||||
}
|
||||
|
||||
ret = dce_admin_channel_init(d);
|
||||
if (ret) {
|
||||
dce_err(d, "Channel Initialization Failed");
|
||||
goto err_channel_init;
|
||||
}
|
||||
|
||||
d->boot_status |= DCE_EARLY_INIT_DONE;
|
||||
return 0;
|
||||
|
||||
err_channel_init:
|
||||
dce_ipc_free_region(d);
|
||||
err_ipc_reg_alloc:
|
||||
d->boot_status |= DCE_EARLY_INIT_FAILED;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_admin_deinit - Releases the resources
|
||||
* associated with admin interface.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
void dce_admin_deinit(struct tegra_dce *d)
|
||||
{
|
||||
dce_admin_channel_deinit(d);
|
||||
|
||||
dce_ipc_free_region(d);
|
||||
|
||||
dce_mailbox_deinit_interface(d,
|
||||
DCE_MAILBOX_ADMIN_INTERFACE);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_admin_allocate_message - Allocates memory for a message
|
||||
* on admin interface.
|
||||
* @d : Pointer tegra_dce struct.
|
||||
*
|
||||
* Return : Allocated msg if successful.
|
||||
*/
|
||||
struct dce_ipc_message *dce_admin_allocate_message(struct tegra_dce *d)
|
||||
{
|
||||
struct dce_ipc_message *msg;
|
||||
|
||||
msg = dce_kzalloc(d, sizeof(*msg), false);
|
||||
if (!msg) {
|
||||
dce_err(d, "Insufficient memory for admin msg");
|
||||
goto err_alloc_msg;
|
||||
}
|
||||
|
||||
msg->tx.data = dce_kzalloc(d, DCE_ADMIN_CMD_SIZE, false);
|
||||
if (!msg->tx.data) {
|
||||
dce_err(d, "Insufficient memory for admin msg");
|
||||
goto err_alloc_tx;
|
||||
}
|
||||
|
||||
msg->rx.data = dce_kzalloc(d, DCE_ADMIN_RESP_SIZE, false);
|
||||
if (!msg->rx.data) {
|
||||
dce_err(d, "Insufficient memory for admin msg");
|
||||
goto err_alloc_rx;
|
||||
}
|
||||
|
||||
msg->tx.size = DCE_ADMIN_CMD_SIZE;
|
||||
msg->rx.size = DCE_ADMIN_RESP_SIZE;
|
||||
|
||||
return msg;
|
||||
|
||||
err_alloc_rx:
|
||||
dce_kfree(d, msg->tx.data);
|
||||
err_alloc_tx:
|
||||
dce_kfree(d, msg);
|
||||
err_alloc_msg:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_admin_free_message - Frees memory allocated for a message
|
||||
* on admin interface.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @msg : Pointer to allocated message.
|
||||
*
|
||||
* Return : Void.
|
||||
*/
|
||||
void dce_admin_free_message(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg)
|
||||
{
|
||||
if (!msg || !msg->tx.data || !msg->rx.data)
|
||||
return;
|
||||
|
||||
dce_kfree(d, msg->tx.data);
|
||||
dce_kfree(d, msg->rx.data);
|
||||
dce_kfree(d, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_admin_send_msg - Sends messages on Admin Channel
|
||||
* synchronously and waits for an ack.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @msg : Pointer to allocated message.
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
int dce_admin_send_msg(struct tegra_dce *d, struct dce_ipc_message *msg)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_admin_send_msg_params params;
|
||||
|
||||
params.msg = msg;
|
||||
|
||||
ret = dce_fsm_post_event(d,
|
||||
EVENT_ID_DCE_ADMIN_IPC_MSG_REQUESTED,
|
||||
(void *)¶ms);
|
||||
if (ret)
|
||||
dce_err(d, "Unable to send msg invalid FSM state");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_admin_send_msg - Sends messages on Admin Channel
|
||||
* synchronously and waits for an ack.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @msg : Pointer to allocated message.
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
int dce_admin_handle_ipc_requested_event(struct tegra_dce *d, void *params)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_ipc_message *msg;
|
||||
struct dce_admin_send_msg_params *admin_params =
|
||||
(struct dce_admin_send_msg_params *)params;
|
||||
|
||||
/*
|
||||
* Do not handle admin IPC if boot commands are not completed
|
||||
*/
|
||||
if (!dce_is_bootcmds_done(d)) {
|
||||
dce_err(d, "Boot commands are not yet completed\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Error check on msg */
|
||||
msg = admin_params->msg;
|
||||
|
||||
ret = dce_ipc_send_message_sync(d, DCE_IPC_CHANNEL_TYPE_ADMIN, msg);
|
||||
if (ret)
|
||||
dce_err(d, "Error sending admin message on admin interface");
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dce_admin_handle_ipc_received_event(struct tegra_dce *d, void *params)
|
||||
{
|
||||
dce_wakeup_interruptible(d, DCE_WAIT_ADMIN_IPC);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_admin_get_ipc_channel_info - Provides channel's
|
||||
* buff details
|
||||
*
|
||||
* @d - Pointer to tegra_dce struct.
|
||||
* @q_info : Pointer to struct dce_ipc_queue_info
|
||||
*
|
||||
* Return - 0 if successful
|
||||
*/
|
||||
int dce_admin_get_ipc_channel_info(struct tegra_dce *d,
|
||||
struct dce_ipc_queue_info *q_info)
|
||||
{
|
||||
int ret;
|
||||
u8 channel_id = DCE_IPC_CHANNEL_TYPE_ADMIN;
|
||||
|
||||
ret = dce_ipc_get_channel_info(d, q_info, channel_id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_admin_send_cmd_echo - Sends DCE_ADMIN_CMD_ECHO cmd.
|
||||
*
|
||||
* @d - Pointer to tegra_dce struct.
|
||||
* @msg - Pointer to dce_ipc_msg struct.
|
||||
*
|
||||
* Return - 0 if successful
|
||||
*/
|
||||
int dce_admin_send_cmd_echo(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;
|
||||
|
||||
/* return if dce bootstrap not completed */
|
||||
if (!dce_is_bootstrap_done(d)) {
|
||||
dce_err(d, "Admin Bootstrap not yet done");
|
||||
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_ECHO;
|
||||
|
||||
ret = dce_admin_send_msg(d, msg);
|
||||
if ((ret) || (resp_msg->error != DCE_ERR_CORE_SUCCESS)) {
|
||||
dce_err(d, "Error sending echo msg : [%d]", ret);
|
||||
ret = ret ? ret : resp_msg->error;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_admin_send_cmd_ext_test - Sends DCE_ADMIN_CMD_EXT_TEST cmd.
|
||||
*
|
||||
* @d - Pointer to tegra_dce struct.
|
||||
* @msg - Pointer to dce_ipc_msg struct.
|
||||
*
|
||||
* Return - 0 if successful
|
||||
*/
|
||||
int dce_admin_send_cmd_ext_test(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;
|
||||
|
||||
/* return if dce bootstrap not completed */
|
||||
if (!dce_is_bootstrap_done(d)) {
|
||||
dce_err(d, "Admin Bootstrap not yet done");
|
||||
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_EXT_TEST;
|
||||
|
||||
ret = dce_admin_send_msg(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "Error sending test msg : [%d]", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_admin_send_cmd_ver - Sends DCE_ADMIN_CMD_VERSION cmd.
|
||||
*
|
||||
* @d - Pointer to tegra_dce struct.
|
||||
* @msg - Pointer to dce_ipc_msg struct.
|
||||
*
|
||||
* Return - 0 if successful
|
||||
*/
|
||||
static int dce_admin_send_cmd_ver(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_admin_ipc_cmd *req_msg;
|
||||
struct dce_admin_ipc_resp *resp_msg;
|
||||
struct dce_admin_version_info *ver_info;
|
||||
|
||||
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_VERSION;
|
||||
ver_info = (struct dce_admin_version_info *)(&resp_msg->args.version);
|
||||
|
||||
ret = dce_admin_send_msg(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "Error sending get version info : [%d]", ret);
|
||||
goto out;
|
||||
}
|
||||
dce_info(d, "version : [0x%x] err : [0x%x]", ver_info->version,
|
||||
resp_msg->error);
|
||||
|
||||
out:
|
||||
/**
|
||||
* TODO : Add more error handling here
|
||||
*/
|
||||
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,
|
||||
struct dce_ipc_message *msg)
|
||||
{
|
||||
uint32_t i;
|
||||
int ret = 0;
|
||||
struct dce_admin_ipc_cmd *req_msg;
|
||||
struct dce_admin_ipc_resp *resp_msg;
|
||||
struct dce_ipc_queue_info q_info;
|
||||
struct dce_admin_ipc_create_args *ipc_info;
|
||||
|
||||
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_IPC_CREATE;
|
||||
ipc_info = (struct dce_admin_ipc_create_args *)
|
||||
(&req_msg->args.ipc_create);
|
||||
|
||||
for (i = 0; i < DCE_IPC_CH_KMD_TYPE_MAX; i++) {
|
||||
if (i == DCE_IPC_CH_KMD_TYPE_ADMIN)
|
||||
continue;
|
||||
ret = dce_ipc_get_channel_info(d, &q_info, i);
|
||||
if (ret) {
|
||||
dce_info(d, "Get queue info failed for [%u]", i);
|
||||
ret = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
ipc_info->type = dce_ipc_get_ipc_type(d, i);
|
||||
ipc_info->rd_iova = q_info.tx_iova;
|
||||
ipc_info->wr_iova = q_info.rx_iova;
|
||||
ipc_info->fsize = q_info.frame_sz;
|
||||
ipc_info->n_frames = q_info.nframes;
|
||||
|
||||
ret = dce_admin_send_msg(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "Error sending IPC create msg for type [%u]",
|
||||
i);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (resp_msg->error != DCE_ERR_CORE_SUCCESS) {
|
||||
dce_err(d, "IPC create for type [%u] failed", i);
|
||||
goto out;
|
||||
}
|
||||
|
||||
dce_ipc_channel_reset(d, i);
|
||||
dce_info(d, "Channel Reset Complete for Type [%u] ...", i);
|
||||
}
|
||||
|
||||
out:
|
||||
/**
|
||||
* TODO : Add more error handling here
|
||||
*/
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dce_admin_send_rm_bootstrap(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_admin_ipc_cmd *req_msg;
|
||||
struct dce_admin_ipc_resp *resp_msg;
|
||||
struct dce_admin_version_info *ver_info;
|
||||
|
||||
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_RM_BOOTSTRAP;
|
||||
ver_info = (struct dce_admin_version_info *)(&resp_msg->args.version);
|
||||
|
||||
ret = dce_admin_send_msg(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "Error sending rm bootstrap cmd: [%d]", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (resp_msg->error != DCE_ERR_CORE_SUCCESS) {
|
||||
dce_err(d, "Error in handling rm bootstrap cmd on dce: [0x%x]",
|
||||
resp_msg->error);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
out:
|
||||
/**
|
||||
* TODO : Add more error handling here
|
||||
*/
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dce_start_admin_seq(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_ipc_message *msg;
|
||||
|
||||
msg = dce_admin_allocate_message(d);
|
||||
if (!msg)
|
||||
return -1;
|
||||
|
||||
d->boot_status |= DCE_FW_ADMIN_SEQ_START;
|
||||
ret = dce_admin_send_cmd_ver(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "RPC failed for DCE_ADMIN_CMD_VERSION");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = dce_admin_setup_clients_ipc(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "RPC failed for DCE_ADMIN_CMD_IPC_CREATE");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = dce_admin_send_rm_bootstrap(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "RPC failed for DCE_ADMIN_CMD_RM_BOOTSTRAP");
|
||||
goto out;
|
||||
}
|
||||
d->boot_status |= DCE_FW_ADMIN_SEQ_DONE;
|
||||
out:
|
||||
dce_admin_free_message(d, msg);
|
||||
if (ret)
|
||||
d->boot_status |= DCE_FW_ADMIN_SEQ_FAILED;
|
||||
return ret;
|
||||
}
|
||||
572
drivers/platform/tegra/dce/dce-ast.c
Normal file
572
drivers/platform/tegra/dce/dce-ast.c
Normal file
@@ -0,0 +1,572 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2023, NVIDIA CORPORATION. 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>
|
||||
#include <dce-log.h>
|
||||
#include <dce-util-common.h>
|
||||
|
||||
#define MAX_NO_ASTS 2
|
||||
#define MAX_AST_REGIONS 1
|
||||
#define MAX_AST_STRMCTLS 2
|
||||
|
||||
#define AST_MASTER_ADDR_HI_BITS_SHIFT 32
|
||||
|
||||
/**
|
||||
* dce_config_ast0_control - programs the global
|
||||
* ast control register for AST0
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dce_config_ast0_control(struct tegra_dce *d)
|
||||
{
|
||||
u32 val;
|
||||
u32 def_physical;
|
||||
u32 phy_stream_id = dce_get_phys_stream_id(d) <<
|
||||
ast_ast0_control_physstreamid_shift_v();
|
||||
|
||||
if (dce_is_physical_id_valid(d))
|
||||
def_physical = 1 <<
|
||||
ast_ast0_control_carveoutlock_defphysical_shift_v();
|
||||
else
|
||||
def_physical = 0 <<
|
||||
ast_ast0_control_carveoutlock_defphysical_shift_v();
|
||||
|
||||
val = phy_stream_id | ast_ast0_control_carveoutlock_false_f()
|
||||
| def_physical | ast_ast0_control_matcherrctl_decerr_f()
|
||||
| ast_ast0_control_lock_false_f();
|
||||
|
||||
dce_writel(d, ast_ast0_control_r(), val);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_config_ast1_control - programs the global
|
||||
* ast control register for AST1
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dce_config_ast1_control(struct tegra_dce *d)
|
||||
{
|
||||
u32 val;
|
||||
u32 def_physical;
|
||||
u32 phy_stream_id = dce_get_phys_stream_id(d) <<
|
||||
ast_ast1_control_physstreamid_shift_v();
|
||||
|
||||
if (dce_is_physical_id_valid(d))
|
||||
def_physical = 1 <<
|
||||
ast_ast1_control_carveoutlock_defphysical_shift_v();
|
||||
else
|
||||
def_physical = 0 <<
|
||||
ast_ast1_control_carveoutlock_defphysical_shift_v();
|
||||
|
||||
val = phy_stream_id | ast_ast1_control_carveoutlock_false_f()
|
||||
| def_physical | ast_ast1_control_matcherrctl_decerr_f()
|
||||
| ast_ast1_control_lock_false_f();
|
||||
|
||||
dce_writel(d, ast_ast1_control_r(), val);
|
||||
}
|
||||
|
||||
/**
|
||||
* ast_ctl_fn is an array of read-only pointers
|
||||
* to a function returning void.
|
||||
*
|
||||
* Contains all the functions to program the global
|
||||
* ast control registers defined above.
|
||||
*/
|
||||
static void (*const ast_ctl_fn[MAX_NO_ASTS])(struct tegra_dce *d) = {
|
||||
|
||||
dce_config_ast0_control,
|
||||
dce_config_ast1_control,
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_cfg_ast0_streamid_ctl_0 - programs the ast streamid
|
||||
* control register for AST0 and Control0
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dce_cfg_ast0_streamid_ctl_0(struct tegra_dce *d)
|
||||
{
|
||||
u32 stream_id_en;
|
||||
u32 dce_stream_id = dce_get_dce_stream_id(d);
|
||||
|
||||
if (dce_is_physical_id_valid(d))
|
||||
stream_id_en = ast_ast0_streamid_ctl_0_enable_disable_f();
|
||||
else
|
||||
stream_id_en = ast_ast0_streamid_ctl_0_enable_enable_f();
|
||||
|
||||
dce_writel(d, ast_ast0_streamid_ctl_0_r(),
|
||||
(dce_stream_id << ast_ast0_streamid_ctl_0_streamid_shift_v()) |
|
||||
stream_id_en);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_cfg_ast0_streamid_ctl_1 - programs the ast streamid
|
||||
* control register for AST0 and Control1
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dce_cfg_ast0_streamid_ctl_1(struct tegra_dce *d)
|
||||
{
|
||||
u32 stream_id_en;
|
||||
u32 dce_stream_id = dce_get_dce_stream_id(d);
|
||||
|
||||
if (dce_is_physical_id_valid(d))
|
||||
stream_id_en = ast_ast0_streamid_ctl_1_enable_disable_f();
|
||||
else
|
||||
stream_id_en = ast_ast0_streamid_ctl_1_enable_enable_f();
|
||||
|
||||
dce_writel(d, ast_ast0_streamid_ctl_1_r(), (dce_stream_id <<
|
||||
ast_ast0_streamid_ctl_1_streamid_shift_v()) |
|
||||
stream_id_en);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_cfg_ast1_streamid_ctl_0 - programs the ast streamid
|
||||
* control register for AST1 and Control0
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dce_cfg_ast1_streamid_ctl_0(struct tegra_dce *d)
|
||||
{
|
||||
u32 stream_id_en;
|
||||
u32 dce_stream_id = dce_get_dce_stream_id(d);
|
||||
|
||||
if (dce_is_physical_id_valid(d))
|
||||
stream_id_en = ast_ast1_streamid_ctl_0_enable_disable_f();
|
||||
else
|
||||
stream_id_en = ast_ast1_streamid_ctl_0_enable_enable_f();
|
||||
|
||||
dce_writel(d, ast_ast1_streamid_ctl_0_r(),
|
||||
(dce_stream_id << ast_ast1_streamid_ctl_0_streamid_shift_v()) |
|
||||
stream_id_en);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_cfg_ast1_streamid_ctl_1 - programs the ast streamid
|
||||
* control register for AST1 and Control1
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dce_cfg_ast1_streamid_ctl_1(struct tegra_dce *d)
|
||||
{
|
||||
u32 stream_id_en;
|
||||
u32 dce_stream_id = dce_get_dce_stream_id(d);
|
||||
|
||||
if (dce_is_physical_id_valid(d))
|
||||
stream_id_en = ast_ast1_streamid_ctl_1_enable_disable_f();
|
||||
else
|
||||
stream_id_en = ast_ast1_streamid_ctl_1_enable_enable_f();
|
||||
|
||||
dce_writel(d, ast_ast1_streamid_ctl_1_r(),
|
||||
(dce_stream_id << ast_ast1_streamid_ctl_1_streamid_shift_v()) |
|
||||
stream_id_en);
|
||||
}
|
||||
|
||||
/**
|
||||
* ast_strmidctl_fn is a 2D array of read-only pointers
|
||||
* to a function returning void.
|
||||
*
|
||||
* Contains all the functions to program the streamId
|
||||
* controls registers defined above for a given AST and Control ID
|
||||
*/
|
||||
static void (*const ast_strmidctl_fn[MAX_NO_ASTS][MAX_AST_STRMCTLS])
|
||||
(struct tegra_dce *d) = {
|
||||
|
||||
{
|
||||
dce_cfg_ast0_streamid_ctl_0,
|
||||
dce_cfg_ast0_streamid_ctl_1,
|
||||
},
|
||||
{
|
||||
dce_cfg_ast1_streamid_ctl_0,
|
||||
dce_cfg_ast1_streamid_ctl_1,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* dce_set_ast0_slave_addr_32_reg0 - programs the ast slave address
|
||||
* for AST0 and Region0
|
||||
*
|
||||
* @d : Pointer to tegra_dce sturct.
|
||||
* @addr : Address to be programmed.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dce_set_ast0_slave_addr_32_reg0(struct tegra_dce *d, u32 addr)
|
||||
{
|
||||
dce_writel(d, ast_ast0_region_0_slave_base_lo_r(),
|
||||
(addr | ast_ast0_region_0_slave_base_lo_enable_true_f()) &
|
||||
ast_ast1_region_0_slave_base_lo_write_mask_v());
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_set_ast1_slave_addr_32_reg0- programs the ast slave address
|
||||
* for AST1 and Region0
|
||||
*
|
||||
* @d : Pointer to tegra_dce sturct.
|
||||
* @addr : Address to be programmed.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dce_set_ast1_slave_addr_32_reg0(struct tegra_dce *d, u32 addr)
|
||||
{
|
||||
dce_writel(d, ast_ast1_region_0_slave_base_lo_r(),
|
||||
(addr | ast_ast1_region_0_slave_base_lo_enable_true_f()) &
|
||||
ast_ast1_region_0_slave_base_lo_write_mask_v());
|
||||
}
|
||||
|
||||
/**
|
||||
* ast_slave_addr_fn is a 2D array of read-only pointers
|
||||
* to a function returning void.
|
||||
*
|
||||
* Contains all the functions to program the slave address and
|
||||
* other bits in salve address registers defined above for a
|
||||
* given AST and region.
|
||||
*/
|
||||
static void (*const ast_slave_addr_fn[MAX_NO_ASTS][MAX_AST_REGIONS])
|
||||
(struct tegra_dce *d, u32 addr) = {
|
||||
|
||||
{
|
||||
dce_set_ast0_slave_addr_32_reg0,
|
||||
},
|
||||
{
|
||||
dce_set_ast1_slave_addr_32_reg0,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_set_ast0_master_addr_lo_reg0 - programs the lower 32 bits of ast
|
||||
* master address for AST0 and Region0
|
||||
*
|
||||
* @d : Pointer to tegra_dce sturct.
|
||||
* @addr : Address to be programmed.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static inline void
|
||||
dce_set_ast0_master_addr_lo_reg0(struct tegra_dce *d, u32 addr)
|
||||
{
|
||||
dce_writel(d, ast_ast0_region_0_master_base_lo_r(), addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_set_ast1_master_addr_lo_reg0 - programs the lower 32 bits of ast
|
||||
* master address for AST1 and Region0
|
||||
*
|
||||
* @d : Pointer to tegra_dce sturct.
|
||||
* @addr : Address to be programmed.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static inline void
|
||||
dce_set_ast1_master_addr_lo_reg0(struct tegra_dce *d, u32 addr)
|
||||
{
|
||||
dce_writel(d, ast_ast1_region_0_master_base_lo_r(), addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_set_ast1_master_addr_hi_reg0 - programs the high 32 bits of ast
|
||||
* master address for AST1 and Region0
|
||||
*
|
||||
* @d : Pointer to tegra_dce sturct.
|
||||
* @addr : Address to be programmed.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static inline void
|
||||
dce_set_ast1_master_addr_hi_reg0(struct tegra_dce *d, u32 addr)
|
||||
{
|
||||
dce_writel(d, ast_ast1_region_0_master_base_hi_r(), addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_set_ast0_master_addr_hi_reg0 - programs the high 32 bits of ast
|
||||
* master address for AST0 and Region0
|
||||
*
|
||||
* @d : Pointer to tegra_dce sturct.
|
||||
* @addr : Address to be programmed.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static inline void
|
||||
dce_set_ast0_master_addr_hi_reg0(struct tegra_dce *d, u32 addr)
|
||||
{
|
||||
dce_writel(d, ast_ast0_region_0_master_base_hi_r(), addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_set_ast0_master_addr_reg0 - programs the ast master address
|
||||
* for AST0 and Region0
|
||||
*
|
||||
* @d : Pointer to tegra_dce sturct.
|
||||
* @addr : Address to be programmed.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dce_set_ast0_master_addr_reg0(struct tegra_dce *d, u64 addr)
|
||||
{
|
||||
u32 ast_master_hi;
|
||||
u32 ast_master_lo;
|
||||
|
||||
ast_master_lo = addr & ast_ast0_region_0_master_base_lo_write_mask_v();
|
||||
dce_set_ast0_master_addr_lo_reg0(d, ast_master_lo);
|
||||
|
||||
ast_master_hi = addr >> AST_MASTER_ADDR_HI_BITS_SHIFT;
|
||||
dce_set_ast0_master_addr_hi_reg0(d, ast_master_hi);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_set_ast1_master_addr_reg0 - programs the ast master address
|
||||
* for AST0 and Region0
|
||||
*
|
||||
* @d : Pointer to tegra_dce sturct.
|
||||
* @addr : Address to be programmed.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dce_set_ast1_master_addr_reg0(struct tegra_dce *d, u64 addr)
|
||||
{
|
||||
u32 ast_master_hi;
|
||||
u32 ast_master_lo;
|
||||
|
||||
ast_master_lo = addr & ast_ast0_region_0_master_base_lo_write_mask_v();
|
||||
dce_set_ast1_master_addr_lo_reg0(d, ast_master_lo);
|
||||
|
||||
ast_master_hi = addr >> AST_MASTER_ADDR_HI_BITS_SHIFT;
|
||||
dce_set_ast1_master_addr_hi_reg0(d, ast_master_hi);
|
||||
}
|
||||
|
||||
/**
|
||||
* ast_master_addr_fn is a 2D array of read-only pointers
|
||||
* to a function returning void.
|
||||
*
|
||||
* Contains all the functions to program the master address registers
|
||||
* defined above for a given AST and region.
|
||||
*/
|
||||
static void (*const ast_master_addr_fn[MAX_NO_ASTS][MAX_AST_REGIONS])
|
||||
(struct tegra_dce *d, u64 addr) = {
|
||||
|
||||
{
|
||||
dce_set_ast0_master_addr_reg0,
|
||||
},
|
||||
{
|
||||
dce_set_ast1_master_addr_reg0,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_get_fw_ast_reg_mask - Returns the size mask based on the fw size
|
||||
* for configuring AST region
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
*
|
||||
* If size is 64K(0x10000), mask is 0xffff. If size is 2MB(0x200000), mask is
|
||||
* 0x1FFFFF.
|
||||
*
|
||||
* Ruturns 64 bit mask.
|
||||
*/
|
||||
static u64 dce_get_fw_ast_reg_mask(struct tegra_dce *d)
|
||||
{
|
||||
struct dce_firmware *fw = d->fw_data;
|
||||
|
||||
return fw->size - 1UL;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_ast_cfg_reg_mask_ast0_reg0 - sets the region mask based on the size
|
||||
* of the DRAM memory for AST0 and Region0.
|
||||
*
|
||||
* @d : pointer to tegra_dce struct
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dce_ast_cfg_reg_mask_ast0_reg0(struct tegra_dce *d)
|
||||
{
|
||||
u64 size_mask = dce_get_fw_ast_reg_mask(d);
|
||||
u32 val = size_mask & ast_ast0_region_0_mask_lo_write_mask_v();
|
||||
|
||||
dce_writel(d, ast_ast0_region_0_mask_lo_r(), val);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_ast_cfg_reg_mask_ast1_reg0 - sets the region mask based on the size
|
||||
* of the DRAM memory for AST1 and Region0.
|
||||
*
|
||||
* @d : pointer to tegra_dce struct
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dce_ast_cfg_reg_mask_ast1_reg0(struct tegra_dce *d)
|
||||
{
|
||||
u64 size_mask = dce_get_fw_ast_reg_mask(d);
|
||||
u32 val = size_mask & ast_ast1_region_0_mask_lo_write_mask_v();
|
||||
|
||||
dce_writel(d, ast_ast1_region_0_mask_lo_r(), val);
|
||||
}
|
||||
|
||||
/**
|
||||
* ast_mask_fn is a 2D array of read-only pointers
|
||||
* to a function returning void.
|
||||
*
|
||||
* Contains all the functions to program the mask
|
||||
* register bits for a given AST and region.
|
||||
*/
|
||||
static void (*const ast_mask_fn[MAX_NO_ASTS][MAX_AST_REGIONS])
|
||||
(struct tegra_dce *d) = {
|
||||
|
||||
{
|
||||
dce_ast_cfg_reg_mask_ast0_reg0,
|
||||
},
|
||||
{
|
||||
dce_ast_cfg_reg_mask_ast1_reg0,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_ast_cfg_reg_control_ast0_reg0 - Configures the ast region control
|
||||
* register for AST0 and Region0
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dce_ast_cfg_reg_control_ast0_reg0(struct tegra_dce *d)
|
||||
{
|
||||
u32 vm_index;
|
||||
u32 carveout_id;
|
||||
u32 use_physical_id;
|
||||
|
||||
if (dce_is_physical_id_valid(d)) {
|
||||
use_physical_id = 1 <<
|
||||
ast_ast0_region_0_control_physical_shift_v();
|
||||
vm_index = 0 <<
|
||||
ast_ast0_region_0_control_vmindex_shift_v();
|
||||
} else {
|
||||
use_physical_id = 0 <<
|
||||
ast_ast0_region_0_control_physical_shift_v();
|
||||
vm_index = dce_get_fw_vm_index(d) <<
|
||||
ast_ast0_region_0_control_vmindex_shift_v();
|
||||
}
|
||||
carveout_id = dce_get_fw_carveout_id(d) <<
|
||||
ast_ast0_region_0_control_carveoutid_shift_v();
|
||||
|
||||
dce_writel(d, ast_ast0_region_0_control_r(),
|
||||
use_physical_id | vm_index | carveout_id |
|
||||
ast_ast0_region_0_control_snoop_enable_f());
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_ast_cfg_reg_control_ast1_reg0 - Configures the ast region control
|
||||
* register for AST1 and Region0
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dce_ast_cfg_reg_control_ast1_reg0(struct tegra_dce *d)
|
||||
{
|
||||
u32 vm_index;
|
||||
u32 carveout_id;
|
||||
u32 use_physical_id;
|
||||
|
||||
if (dce_is_physical_id_valid(d)) {
|
||||
use_physical_id = 1 <<
|
||||
ast_ast1_region_0_control_physical_shift_v();
|
||||
vm_index = 0 <<
|
||||
ast_ast1_region_0_control_vmindex_shift_v();
|
||||
} else {
|
||||
use_physical_id = 0 <<
|
||||
ast_ast1_region_0_control_physical_shift_v();
|
||||
vm_index = dce_get_fw_vm_index(d) <<
|
||||
ast_ast1_region_0_control_vmindex_shift_v();
|
||||
}
|
||||
|
||||
carveout_id = dce_get_fw_carveout_id(d) <<
|
||||
ast_ast1_region_0_control_carveoutid_shift_v();
|
||||
|
||||
|
||||
dce_writel(d, ast_ast1_region_0_control_r(),
|
||||
use_physical_id | vm_index | carveout_id |
|
||||
ast_ast1_region_0_control_snoop_enable_f());
|
||||
}
|
||||
|
||||
/**
|
||||
* ast_reg_control_fn is a 2D array of read-only pointers
|
||||
* to a function returning void.
|
||||
*
|
||||
* Contains all the functions to program the region control
|
||||
* register bits given AST and region.
|
||||
*/
|
||||
static void (*const ast_reg_control_fn[MAX_NO_ASTS][MAX_AST_REGIONS])
|
||||
(struct tegra_dce *d) = {
|
||||
|
||||
{
|
||||
dce_ast_cfg_reg_control_ast0_reg0,
|
||||
},
|
||||
{
|
||||
dce_ast_cfg_reg_control_ast1_reg0,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_config_ast - Configures the a AST region for initial loading of fw
|
||||
* platform data.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
void dce_config_ast(struct tegra_dce *d)
|
||||
{
|
||||
u8 i;
|
||||
u8 j;
|
||||
u32 slave_addr;
|
||||
u64 master_addr;
|
||||
|
||||
d->boot_status |= DCE_AST_CONFIG_START;
|
||||
slave_addr = dce_get_fw_dce_addr(d);
|
||||
|
||||
if (!d->fw_data) {
|
||||
dce_err(d, "DCE_BOOT_FAILED: No fw_data present");
|
||||
d->boot_status |= DCE_AST_CONFIG_FAILED;
|
||||
return;
|
||||
}
|
||||
|
||||
master_addr = d->fw_data->dma_handle;
|
||||
|
||||
for (i = 0; i < MAX_NO_ASTS; i++) {
|
||||
ast_ctl_fn[i](d);
|
||||
|
||||
for (j = 0; j < MAX_AST_STRMCTLS; j++)
|
||||
ast_strmidctl_fn[i][j](d);
|
||||
|
||||
for (j = 0; j < MAX_AST_REGIONS; j++) {
|
||||
ast_mask_fn[i][j](d);
|
||||
ast_reg_control_fn[i][j](d);
|
||||
ast_master_addr_fn[i][j](d, master_addr);
|
||||
ast_slave_addr_fn[i][j](d, slave_addr);
|
||||
}
|
||||
}
|
||||
d->boot_status |= DCE_AST_CONFIG_DONE;
|
||||
}
|
||||
870
drivers/platform/tegra/dce/dce-bootstrap.c
Normal file
870
drivers/platform/tegra/dce/dce-bootstrap.c
Normal file
@@ -0,0 +1,870 @@
|
||||
/*
|
||||
* Copyright (c) 2019-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>
|
||||
#include <dce-util-common.h>
|
||||
#include <interface/dce-interface.h>
|
||||
#include <interface/dce-boot-cmds.h>
|
||||
|
||||
/**
|
||||
* dce_fw_boot_complete - Checks if dce has complelted boot.
|
||||
*
|
||||
* @d - Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : True if boot is complete
|
||||
*/
|
||||
inline bool dce_fw_boot_complete(struct tegra_dce *d)
|
||||
{
|
||||
return !!(dce_ss_get_state(d, DCE_BOOT_SEMA)
|
||||
& DCE_BOOT_COMPLETE);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_request_fw_boot_complete - Requests DCE to raise an
|
||||
* interrupt on boot completion.
|
||||
*
|
||||
* @d - Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
inline void dce_request_fw_boot_complete(struct tegra_dce *d)
|
||||
{
|
||||
#define DCE_BOOT_INIT_BPOS 31U
|
||||
dce_ss_set(d, DCE_BOOT_INIT_BPOS, DCE_BOOT_SEMA);
|
||||
#undef DCE_BOOT_INIT_BPOS
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_handle_boot_cmd_requested_event - callback handler function for event
|
||||
* EVENT_ID_DCE_BOOT_CMD_MSG_REQUESTED
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @params : callback params
|
||||
*
|
||||
* Return : 0 if successful else error code
|
||||
*/
|
||||
int dce_handle_boot_cmd_requested_event(struct tegra_dce *d, void *params)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_mailbox_send_cmd_params *mbox_params =
|
||||
(struct dce_mailbox_send_cmd_params *)params;
|
||||
|
||||
dce_debug(d, "cmd:%u interface:%u", mbox_params->cmd, mbox_params->interface);
|
||||
|
||||
ret = dce_handle_mailbox_send_cmd_sync(d, mbox_params->cmd,
|
||||
mbox_params->interface);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_handle_boot_cmd_received_event - callback handler function for event
|
||||
* EVENT_ID_DCE_BOOT_CMD_MSG_RECEIVED
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @params : callback params
|
||||
*
|
||||
* Return : 0 if successful else error code
|
||||
*/
|
||||
int dce_handle_boot_cmd_received_event(struct tegra_dce *d, void *params)
|
||||
{
|
||||
dce_wakeup_interruptible(d, DCE_WAIT_BOOT_CMD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_handle_boot_complete_requested_event - callback handler function for
|
||||
* event EVENT_ID_DCE_BOOT_COMPLETE_REQUESTED
|
||||
*
|
||||
* Wait for the DCE to boot and be ready to receive commands from CCPLEX driver.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @params : callback params
|
||||
*
|
||||
* Return : 0 if successful else error code
|
||||
*/
|
||||
int dce_handle_boot_complete_requested_event(struct tegra_dce *d, void *params)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
d->boot_status |= DCE_FW_EARLY_BOOT_START;
|
||||
if (dce_fw_boot_complete(d)) {
|
||||
ret = dce_fsm_post_event(d, EVENT_ID_DCE_BOOT_COMPLETE_RECEIVED, NULL);
|
||||
if (ret)
|
||||
dce_err(d, "failed to send DCE_BOOT_COMPLETE_RECEIVED event");
|
||||
|
||||
goto boot_done;
|
||||
}
|
||||
|
||||
dce_request_fw_boot_complete(d);
|
||||
|
||||
dce_debug(d, "Waiting for dce fw to boot...");
|
||||
|
||||
ret = dce_wait_interruptible(d, DCE_WAIT_BOOT_COMPLETE);
|
||||
if (ret) {
|
||||
/**
|
||||
* TODO: Add error handling for abort and retry
|
||||
*/
|
||||
dce_err(d, "dce boot wait was interrupted with err:%d", ret);
|
||||
}
|
||||
|
||||
boot_done:
|
||||
if (!ret) {
|
||||
dce_set_boot_complete(d, true);
|
||||
d->boot_status |= DCE_FW_EARLY_BOOT_DONE;
|
||||
dce_debug(d, "dce is ready to receive bootstrap commands");
|
||||
} else {
|
||||
d->boot_status |= DCE_FW_EARLY_BOOT_FAILED;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_handle_boot_complete_received_event - callback handler function for
|
||||
* event EVENT_ID_DCE_BOOT_CMD_MSG_RECEIVED
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @params : callback params
|
||||
*
|
||||
* Return : 0 if successful else error code
|
||||
*/
|
||||
int dce_handle_boot_complete_received_event(struct tegra_dce *d, void *params)
|
||||
{
|
||||
dce_wakeup_interruptible(d, DCE_WAIT_BOOT_COMPLETE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* dce_start_boot_flow : Start dce bootstrap flow
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : 0 if successful else error code
|
||||
*/
|
||||
int
|
||||
dce_start_boot_flow(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = dce_start_bootstrap_flow(d);
|
||||
if (ret) {
|
||||
dce_err(d, "DCE_BOOT_FAILED: Bootstrap flow didn't complete");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
dce_admin_ivc_channel_reset(d);
|
||||
|
||||
ret = dce_start_admin_seq(d);
|
||||
if (ret) {
|
||||
dce_err(d, "DCE_BOOT_FAILED: Admin flow didn't complete");
|
||||
} else {
|
||||
d->boot_status |= DCE_FW_BOOT_DONE;
|
||||
dce_info(d, "DCE_BOOT_DONE");
|
||||
dce_cond_broadcast_interruptible(&d->dce_bootstrap_done);
|
||||
}
|
||||
|
||||
exit:
|
||||
if (ret)
|
||||
d->boot_status |= DCE_STATUS_FAILED;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_bootstrap_work_fn : execute fsm start and bootstrap flow
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
void dce_bootstrap_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_FSM_START, NULL);
|
||||
if (ret) {
|
||||
dce_err(d, "FSM start failed\n");
|
||||
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_irq_status - Handles irq status from DCE
|
||||
*
|
||||
* @d : Pointer to struct tegra_dce
|
||||
* @status : Status received from DCE
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dce_handle_irq_status(struct tegra_dce *d, u32 status)
|
||||
{
|
||||
|
||||
if (status & DCE_IRQ_LOG_OVERFLOW)
|
||||
dce_info(d, "DCE trace log overflow error received");
|
||||
|
||||
if (status & DCE_IRQ_CRASH_LOG)
|
||||
dce_info(d, "DCE crash log available");
|
||||
|
||||
if (status & DCE_IRQ_ABORT)
|
||||
dce_err(d, "DCE ucode abort occurred");
|
||||
|
||||
if (status & DCE_IRQ_READY) {
|
||||
dce_debug(d, "DCE IRQ Ready Received");
|
||||
(void)dce_fsm_post_event(d,
|
||||
EVENT_ID_DCE_BOOT_COMPLETE_RECEIVED,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (status & DCE_IRQ_SC7_ENTERED) {
|
||||
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) {
|
||||
dce_info(d, "DCE trace log buffers available");
|
||||
dce_wakeup_interruptible(d, DCE_WAIT_LOG);
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: handle individual bits
|
||||
*/
|
||||
if (status & (DCE_IRQ_LOG_OVERFLOW | DCE_IRQ_CRASH_LOG |
|
||||
DCE_IRQ_ABORT)) {
|
||||
// Wrapper function around this ??
|
||||
// TODO: Wake All other waiting processes
|
||||
(void) dce_fsm_post_event(d, EVENT_ID_DCE_ABORT_RECEIVED, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* dce_bootstrap_handle_boot_status- Handles boot status from DCE
|
||||
*
|
||||
* @d : Pointer to struct tegra_dce
|
||||
* @status : Status received from DCE
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dce_bootstrap_handle_boot_status(struct tegra_dce *d, u32 status)
|
||||
{
|
||||
int ret = 0;
|
||||
dce_mailbox_store_interface_status(d, status,
|
||||
DCE_MAILBOX_BOOT_INTERFACE);
|
||||
|
||||
ret = dce_fsm_post_event(d, EVENT_ID_DCE_BOOT_CMD_MSG_RECEIVED, NULL);
|
||||
if (ret)
|
||||
dce_err(d, "Mbox bootstrap cmd failed");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* dce_boot_interface_isr - Isr for the CCPLEX<->DCE boot interface.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dce_boot_interface_isr(struct tegra_dce *d, void *data)
|
||||
{
|
||||
u32 status;
|
||||
u8 interface_id = DCE_MAILBOX_BOOT_INTERFACE;
|
||||
|
||||
status = dce_mailbox_get_interface_status(d, interface_id);
|
||||
if (status == 0xffffffff)
|
||||
return;
|
||||
|
||||
switch (DCE_IRQ_GET_STATUS_TYPE(status)) {
|
||||
case DCE_IRQ_STATUS_TYPE_IRQ:
|
||||
dce_handle_irq_status(d, status);
|
||||
break;
|
||||
case DCE_IRQ_STATUS_TYPE_BOOT_CMD:
|
||||
dce_bootstrap_handle_boot_status(d, status);
|
||||
break;
|
||||
default:
|
||||
dce_info(d, "Invalid Status Received from DCE. Status: [%x]",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_parse_boot_status_err - Parses the error sent by DCE
|
||||
*
|
||||
* @d : Pointer to struct tegra_dce
|
||||
* @status : Status read from mailbox
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dce_parse_boot_status_err(struct tegra_dce *d, u32 status)
|
||||
{
|
||||
#define DCE_BOOT_ERR_MASK 0x7FFFFF
|
||||
status &= DCE_BOOT_ERR_MASK;
|
||||
#undef DCE_BOOT_ERR_MASK
|
||||
|
||||
switch (status) {
|
||||
case DCE_BOOT_CMD_ERR_BAD_COMMAND:
|
||||
dce_info(d, "Boot Status Error : DCE_BOOT_CMD_ERR_BAD_COMMAND");
|
||||
break;
|
||||
case DCE_BOOT_CMD_ERR_UNIMPLEMENTED:
|
||||
dce_info(d, "Boot Status Error : DCE_BOOT_CMD_ERR_UNIMPLEMENTED");
|
||||
break;
|
||||
case DCE_BOOT_CMD_ERR_IPC_SETUP:
|
||||
dce_info(d, "Boot Status Error : DCE_BOOT_CMD_ERR_IPC_SETUP");
|
||||
break;
|
||||
case DCE_BOOT_CMD_ERR_INVALID_NFRAMES:
|
||||
dce_info(d, "Boot Status Error : DCE_BOOT_CMD_ERR_INVALID_NFRAMES");
|
||||
break;
|
||||
case DCE_BOOT_CMD_ERR_IPC_CREATE:
|
||||
dce_info(d, "Boot Status Error : DCE_BOOT_CMD_ERR_IPC_CREATE");
|
||||
break;
|
||||
case DCE_BOOT_CMD_ERR_LOCKED:
|
||||
dce_info(d, "Boot Status Error : DCE_BOOT_CMD_ERR_LOCKED");
|
||||
break;
|
||||
default:
|
||||
dce_info(d, "Invalid Error Status Rcvd. Status: [%x]", status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_mailbox_wait_boot_interface - Waits for mailbox messages.
|
||||
*
|
||||
* @d : Pointer to tegra_dce
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
static int dce_mailbox_wait_boot_interface(struct tegra_dce *d)
|
||||
{
|
||||
u32 status;
|
||||
int ret;
|
||||
|
||||
ret = dce_wait_interruptible(d, DCE_WAIT_BOOT_CMD);
|
||||
if (ret) {
|
||||
/**
|
||||
* TODO: Add error handling for abort and retry
|
||||
*/
|
||||
dce_err(d, "dce mbox wait was interrupted with err:%d", ret);
|
||||
}
|
||||
|
||||
status = dce_mailbox_get_interface_status(d,
|
||||
DCE_MAILBOX_BOOT_INTERFACE);
|
||||
|
||||
if (status & DCE_BOOT_CMD_ERR_FLAG) {
|
||||
dce_parse_boot_status_err(d, status);
|
||||
dce_err(d, "Error code received on boot interface : 0x%x",
|
||||
status);
|
||||
return -EBADE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_boot_interface_init - Initializes the dce boot interface
|
||||
* and the associated resources.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
int dce_boot_interface_init(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
u8 mailbox_id = DCE_MAILBOX_BOOT_INTERFACE;
|
||||
|
||||
ret = dce_mailbox_init_interface(d, mailbox_id,
|
||||
DCE_MBOX_BOOT_CMD, DCE_MBOX_IRQ,
|
||||
dce_mailbox_wait_boot_interface,
|
||||
NULL, dce_boot_interface_isr);
|
||||
if (ret) {
|
||||
dce_err(d, "Boot Mailbox Interface Init Failed");
|
||||
goto err_init;
|
||||
}
|
||||
|
||||
err_init:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_boot_interface_deinit - Releases the resources
|
||||
* associated with dce boot.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
void dce_boot_interface_deinit(struct tegra_dce *d)
|
||||
{
|
||||
dce_mailbox_deinit_interface(d,
|
||||
DCE_MAILBOX_BOOT_INTERFACE);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_send_version_cmd - Sends the "VERSION" command to dce fw
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
static int dce_send_version_cmd(struct tegra_dce *d)
|
||||
{
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
|
||||
val = DCE_BOOT_CMD_SET(0U, DCE_BOOT_CMD_VERSION);
|
||||
|
||||
ret = dce_mailbox_send_cmd_sync(d, val, DCE_MAILBOX_BOOT_INTERFACE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_send_set_sid_cmd - Sends the "SET_SID" command to dce fw
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
static int dce_send_set_sid_cmd(struct tegra_dce *d)
|
||||
{
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
|
||||
val = DCE_BOOT_CMD_SET(0U, DCE_BOOT_CMD_SET_SID) |
|
||||
DCE_BOOT_CMD_PARM_SET(0, dce_get_dce_stream_id(d));
|
||||
|
||||
ret = dce_mailbox_send_cmd_sync(d, val, DCE_MAILBOX_BOOT_INTERFACE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_send_channel_int_cmd - Sends the "CHANNEL_INIT" command to dce fw
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
static int dce_send_channel_int_cmd(struct tegra_dce *d)
|
||||
{
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
|
||||
val = DCE_BOOT_CMD_SET(0U, DCE_BOOT_CMD_CHANNEL_INIT);
|
||||
|
||||
ret = dce_mailbox_send_cmd_sync(d, val, DCE_MAILBOX_BOOT_INTERFACE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_send_set_addr_read_cmd_hi - Sends addr_hi cmd to dce fw.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @addr : IOVA addr to be sent.
|
||||
* @rd_wr : Tells if the addr to be sent is for read or write
|
||||
* interface.
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
static int dce_send_set_addr_cmd_hi(struct tegra_dce *d, u32 addr, u8 rd_wr)
|
||||
{
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
|
||||
val = DCE_BOOT_CMD_SET_HILO(0U, 1U) |
|
||||
DCE_BOOT_CMD_SET_RDWR(0U, rd_wr) |
|
||||
DCE_BOOT_CMD_SET(0U, DCE_BOOT_CMD_SET_ADDR) |
|
||||
DCE_BOOT_CMD_PARM_SET(0U, addr);
|
||||
|
||||
ret = dce_mailbox_send_cmd_sync(d, val, DCE_MAILBOX_BOOT_INTERFACE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_send_set_addr_read_cmd_lo - Sends addr_lo cmd to dce fw.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @addr : IOVA addr to be sent.
|
||||
* @rd_wr : Tells if the addr to be sent is for read or write
|
||||
* interface.
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
static int dce_send_set_addr_cmd_lo(struct tegra_dce *d, u32 addr, u8 rd_wr)
|
||||
{
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
|
||||
val = DCE_BOOT_CMD_SET_HILO(0U, 0U) |
|
||||
DCE_BOOT_CMD_SET_RDWR(0U, rd_wr) |
|
||||
DCE_BOOT_CMD_SET(0U, DCE_BOOT_CMD_SET_ADDR) |
|
||||
DCE_BOOT_CMD_PARM_SET(0U, addr);
|
||||
|
||||
ret = dce_mailbox_send_cmd_sync(d, val, DCE_MAILBOX_BOOT_INTERFACE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_send_set_addr_read_cmd - Sends the addresses for admin
|
||||
* read interface to dce fw.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
* @rd_buff : Read address
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
static int dce_send_set_addr_read_cmd(struct tegra_dce *d, const u64 rd_buff)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#define DCE_DATA_NBITS_SHIFT 20
|
||||
ret = dce_send_set_addr_cmd_hi(d, rd_buff >> DCE_DATA_NBITS_SHIFT, 0);
|
||||
if (ret) {
|
||||
dce_err(d, "Sending of SEND_ADDR for READ IOVA HI failed");
|
||||
goto err_sending;
|
||||
}
|
||||
|
||||
ret = dce_send_set_addr_cmd_lo(d, rd_buff, 0);
|
||||
if (ret) {
|
||||
dce_err(d, "Sending of SEND_ADDR for READ IOVA LO failed");
|
||||
goto err_sending;
|
||||
}
|
||||
#undef DCE_DATA_NBITS_SHIFT
|
||||
|
||||
err_sending:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_send_set_addr_write_cmd - Sends the addresses for admin
|
||||
* write interface to dce fw.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
* @wr_buff : Write address
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
static int dce_send_set_addr_write_cmd(struct tegra_dce *d, const u64 wr_buff)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#define DCE_DATA_NBITS_SHIFT 20
|
||||
ret = dce_send_set_addr_cmd_hi(d, wr_buff >> DCE_DATA_NBITS_SHIFT, 1);
|
||||
if (ret) {
|
||||
dce_err(d, "Sending of SEND_ADDR for READ IOVA HI failed");
|
||||
goto err_sending;
|
||||
}
|
||||
|
||||
ret = dce_send_set_addr_cmd_lo(d, wr_buff, 1);
|
||||
if (ret) {
|
||||
dce_err(d, "Sending of SEND_ADDR for READ IOVA LO failed");
|
||||
goto err_sending;
|
||||
}
|
||||
#undef DCE_DATA_NBITS_SHIFT
|
||||
|
||||
err_sending:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_send_get_fsize_cmd - Sends the "GET_FSIZE" command to dce fw
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
static int dce_send_get_fsize_cmd(struct tegra_dce *d)
|
||||
{
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
|
||||
val = DCE_BOOT_CMD_SET(0U, DCE_BOOT_CMD_GET_FSIZE);
|
||||
|
||||
ret = dce_mailbox_send_cmd_sync(d, val, DCE_MAILBOX_BOOT_INTERFACE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_send_set_nframes_cmd - Sends the "SET_NFRAMES" command to dce fw.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
* @nframes : No. of frames
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
static int dce_send_set_nframes_cmd(struct tegra_dce *d, const u8 nframes)
|
||||
{
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
|
||||
val = DCE_BOOT_CMD_SET(0U, DCE_BOOT_CMD_SET_NFRAMES)
|
||||
| DCE_BOOT_CMD_PARM_SET(0U, nframes);
|
||||
|
||||
ret = dce_mailbox_send_cmd_sync(d, val, DCE_MAILBOX_BOOT_INTERFACE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_send_set_frames_cmd - Sends the "SET_NFRAMES" command to dce fw.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
* @nframes : No. of frames
|
||||
*
|
||||
* Retrun : 0 if successful
|
||||
*/
|
||||
static int dce_send_set_fsize_cmd(struct tegra_dce *d, const u32 fsize)
|
||||
{
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
|
||||
val = DCE_BOOT_CMD_SET(0U, DCE_BOOT_CMD_SET_FSIZE)
|
||||
| DCE_BOOT_CMD_PARM_SET(0U, fsize);
|
||||
|
||||
ret = dce_mailbox_send_cmd_sync(d, val, DCE_MAILBOX_BOOT_INTERFACE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_send_channel_int_cmd - Sends the "CHANNEL_INIT" command to dce fw
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
static int dce_send_lock_cmd(struct tegra_dce *d)
|
||||
{
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
|
||||
val = DCE_BOOT_CMD_SET(0U, DCE_BOOT_CMD_LOCK);
|
||||
|
||||
ret = dce_mailbox_send_cmd_sync(d, val, DCE_MAILBOX_BOOT_INTERFACE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_bootstrap_send_ast_iova_info - Sends the iova info for AST
|
||||
* channel.
|
||||
*
|
||||
* @d - Pointer to struct tegra_dce.
|
||||
*
|
||||
* Return : O if successful
|
||||
*/
|
||||
static int dce_bootstrap_send_ast_iova_info(struct tegra_dce *d)
|
||||
{
|
||||
u64 iova;
|
||||
u32 size;
|
||||
int ret = 0;
|
||||
|
||||
ret = dce_ipc_get_region_iova_info(d, &iova, &size);
|
||||
if (ret) {
|
||||
dce_err(d, "Failed to get the iova info needed for ast config");
|
||||
goto err_sending;
|
||||
}
|
||||
|
||||
#define DCE_DATA_NBITS_SHIFT 20
|
||||
ret = dce_mailbox_send_cmd_sync(d,
|
||||
DCE_BOOT_CMD_SET_HILO(0U, 1U) |
|
||||
DCE_BOOT_CMD_SET(0U, DCE_BOOT_CMD_SET_AST_LENGTH) |
|
||||
DCE_BOOT_CMD_PARM_SET(0U, size >> DCE_DATA_NBITS_SHIFT),
|
||||
DCE_MAILBOX_BOOT_INTERFACE);
|
||||
if (ret) {
|
||||
dce_err(d, "Sending of bootstrap cmd SET_AST_LENGTH(HI) failed");
|
||||
goto err_sending;
|
||||
}
|
||||
|
||||
ret = dce_mailbox_send_cmd_sync(d,
|
||||
DCE_BOOT_CMD_SET_HILO(0U, 0U) |
|
||||
DCE_BOOT_CMD_SET(0U, DCE_BOOT_CMD_SET_AST_LENGTH) |
|
||||
DCE_BOOT_CMD_PARM_SET(0U, size),
|
||||
DCE_MAILBOX_BOOT_INTERFACE);
|
||||
if (ret) {
|
||||
dce_err(d, "Sending of bootstrap cmd SET_AST_LENGTH(LO) failed");
|
||||
goto err_sending;
|
||||
}
|
||||
|
||||
ret = dce_mailbox_send_cmd_sync(d,
|
||||
DCE_BOOT_CMD_SET_HILO(0U, 1U) |
|
||||
DCE_BOOT_CMD_SET(0U, DCE_BOOT_CMD_SET_AST_IOVA) |
|
||||
DCE_BOOT_CMD_PARM_SET(0U, iova >> DCE_DATA_NBITS_SHIFT),
|
||||
DCE_MAILBOX_BOOT_INTERFACE);
|
||||
if (ret) {
|
||||
dce_err(d, "Sending of bootstrap cmd SET_AST_IOVA(HI) failed");
|
||||
goto err_sending;
|
||||
}
|
||||
#undef DCE_DATA_NBITS_SHIFT
|
||||
|
||||
ret = dce_mailbox_send_cmd_sync(d,
|
||||
DCE_BOOT_CMD_SET_HILO(0U, 0U) |
|
||||
DCE_BOOT_CMD_SET(0U, DCE_BOOT_CMD_SET_AST_IOVA) |
|
||||
DCE_BOOT_CMD_PARM_SET(0U, iova),
|
||||
DCE_MAILBOX_BOOT_INTERFACE);
|
||||
if (ret) {
|
||||
dce_err(d, "Sending of bootstrap cmd SET_AST_IOVA(LO) failed");
|
||||
goto err_sending;
|
||||
}
|
||||
|
||||
err_sending:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_bootstrap_send_admin_ivc_info - Sends the ivc related info for admin
|
||||
* channel.
|
||||
*
|
||||
* @d - Pointer to struct tegra_dce.
|
||||
*
|
||||
* Return : O if successful
|
||||
*/
|
||||
static int dce_bootstrap_send_admin_ivc_info(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 val = 0;
|
||||
|
||||
struct dce_ipc_queue_info q_info;
|
||||
|
||||
ret = dce_admin_get_ipc_channel_info(d, &q_info);
|
||||
if (ret) {
|
||||
dce_err(d, "Failed to get the admin ivc channel info");
|
||||
goto err_sending;
|
||||
}
|
||||
|
||||
ret = dce_send_set_addr_read_cmd(d, (u64)(q_info.tx_iova));
|
||||
if (ret) {
|
||||
dce_err(d, "Sending of bootstrap cmd set_addr_read failed");
|
||||
goto err_sending;
|
||||
}
|
||||
|
||||
ret = dce_send_set_addr_write_cmd(d, (u64)(q_info.rx_iova));
|
||||
if (ret) {
|
||||
dce_err(d, "Sending of bootstrap cmd set_addr_write failed");
|
||||
goto err_sending;
|
||||
}
|
||||
|
||||
ret = dce_send_get_fsize_cmd(d);
|
||||
if (ret) {
|
||||
dce_err(d, "Sending of bootstrap cmd get_fsize failed");
|
||||
goto err_sending;
|
||||
}
|
||||
|
||||
/**
|
||||
* It's assummed here that no other command is sent in between.
|
||||
*/
|
||||
val = dce_mailbox_get_interface_status(d,
|
||||
DCE_MAILBOX_BOOT_INTERFACE);
|
||||
|
||||
ret = dce_send_set_nframes_cmd(d, q_info.nframes);
|
||||
if (ret) {
|
||||
dce_err(d, "Sending of bootstrap cmd set_nframes failed");
|
||||
goto err_sending;
|
||||
}
|
||||
|
||||
ret = dce_send_set_fsize_cmd(d, q_info.frame_sz);
|
||||
if (ret) {
|
||||
dce_err(d, "Sending of bootstrap cmd set_fsize failed");
|
||||
goto err_sending;
|
||||
}
|
||||
|
||||
err_sending:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_start_bootstrap_flow - Starts sending the boostrap cmds to
|
||||
* dce fw in the required sequence.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
int dce_start_bootstrap_flow(struct tegra_dce *d)
|
||||
{
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
|
||||
d->boot_status |= DCE_FW_BOOTSTRAP_START;
|
||||
ret = dce_send_version_cmd(d);
|
||||
if (ret) {
|
||||
dce_err(d, "Sending of bootstrap cmd VERSION failed");
|
||||
goto err_sending;
|
||||
}
|
||||
/**
|
||||
* It's assummed here that no other command is sent in between.
|
||||
*/
|
||||
val = dce_mailbox_get_interface_status(d,
|
||||
DCE_MAILBOX_BOOT_INTERFACE);
|
||||
|
||||
ret = dce_send_set_sid_cmd(d);
|
||||
if (ret) {
|
||||
dce_err(d, "Sending of bootstrap cmd set_sid failed");
|
||||
goto err_sending;
|
||||
}
|
||||
|
||||
ret = dce_bootstrap_send_ast_iova_info(d);
|
||||
if (ret) {
|
||||
dce_err(d, "Sending of iova info failed");
|
||||
goto err_sending;
|
||||
}
|
||||
|
||||
ret = dce_bootstrap_send_admin_ivc_info(d);
|
||||
if (ret) {
|
||||
dce_err(d, "Sending of ivc channel info failedbootstrap cmd set_sid failed");
|
||||
goto err_sending;
|
||||
}
|
||||
|
||||
ret = dce_send_channel_int_cmd(d);
|
||||
if (ret) {
|
||||
dce_err(d, "Sending of bootstrap cmd channel_int failed");
|
||||
goto err_sending;
|
||||
}
|
||||
|
||||
ret = dce_send_lock_cmd(d);
|
||||
if (ret) {
|
||||
dce_err(d, "Sending of bootstrap cmd lock failed");
|
||||
goto err_sending;
|
||||
}
|
||||
|
||||
d->boot_status |= DCE_FW_BOOTSTRAP_DONE;
|
||||
return 0;
|
||||
|
||||
err_sending:
|
||||
dce_err(d, "Bootstrap process failed");
|
||||
d->boot_status |= DCE_FW_BOOTSTRAP_FAILED;
|
||||
return ret;
|
||||
}
|
||||
386
drivers/platform/tegra/dce/dce-client-ipc.c
Normal file
386
drivers/platform/tegra/dce/dce-client-ipc.c
Normal file
@@ -0,0 +1,386 @@
|
||||
/*
|
||||
* Copyright (c) 2019-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>
|
||||
#include <dce-ipc.h>
|
||||
#include <dce-util-common.h>
|
||||
#include <dce-client-ipc-internal.h>
|
||||
|
||||
#define DCE_IPC_HANDLES_MAX 6U
|
||||
#define DCE_CLIENT_IPC_HANDLE_INVALID 0U
|
||||
#define DCE_CLIENT_IPC_HANDLE_VALID ((u32)BIT(31))
|
||||
|
||||
static struct tegra_dce_client_ipc client_handles[DCE_CLIENT_IPC_TYPE_MAX];
|
||||
|
||||
static uint32_t dce_interface_type_map[DCE_CLIENT_IPC_TYPE_MAX] = {
|
||||
[DCE_CLIENT_IPC_TYPE_CPU_RM] = DCE_IPC_TYPE_DISPRM,
|
||||
[DCE_CLIENT_IPC_TYPE_HDCP_KMD] = DCE_IPC_TYPE_HDCP,
|
||||
[DCE_CLIENT_IPC_TYPE_RM_EVENT] = DCE_IPC_TYPE_RM_NOTIFY,
|
||||
};
|
||||
|
||||
static void dce_client_process_event_ipc(struct tegra_dce *d,
|
||||
struct tegra_dce_client_ipc *cl);
|
||||
|
||||
static inline uint32_t dce_client_get_type(uint32_t int_type)
|
||||
{
|
||||
uint32_t lc = 0;
|
||||
|
||||
for (lc = 0; lc < DCE_CLIENT_IPC_TYPE_MAX; lc++)
|
||||
if (dce_interface_type_map[lc] == int_type)
|
||||
break;
|
||||
|
||||
return lc;
|
||||
}
|
||||
|
||||
static inline u32 client_handle_to_index(u32 handle)
|
||||
{
|
||||
return (u32)(handle & ~DCE_CLIENT_IPC_HANDLE_VALID);
|
||||
}
|
||||
|
||||
static inline bool is_client_handle_valid(u32 handle)
|
||||
{
|
||||
bool valid = false;
|
||||
|
||||
if ((handle & DCE_CLIENT_IPC_HANDLE_VALID) == 0U)
|
||||
goto out;
|
||||
|
||||
if (client_handle_to_index(handle) >= DCE_CLIENT_IPC_TYPE_MAX)
|
||||
goto out;
|
||||
|
||||
valid = true;
|
||||
|
||||
out:
|
||||
return valid;
|
||||
}
|
||||
|
||||
static struct tegra_dce_client_ipc *dce_client_ipc_lookup_handle(u32 handle)
|
||||
{
|
||||
struct tegra_dce_client_ipc *cl = NULL;
|
||||
|
||||
if (!is_client_handle_valid(handle))
|
||||
goto out;
|
||||
|
||||
cl = &client_handles[client_handle_to_index(handle)];
|
||||
|
||||
out:
|
||||
return cl;
|
||||
}
|
||||
|
||||
|
||||
static int dce_client_ipc_handle_alloc(u32 *handle)
|
||||
{
|
||||
u32 index;
|
||||
int ret = -1;
|
||||
|
||||
if (handle == NULL)
|
||||
return ret;
|
||||
|
||||
for (index = 0; index < DCE_CLIENT_IPC_TYPE_MAX; index++) {
|
||||
if (client_handles[index].valid == false) {
|
||||
client_handles[index].valid = true;
|
||||
*handle = (u32)(index | DCE_CLIENT_IPC_HANDLE_VALID);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dce_client_ipc_handle_free(u32 handle)
|
||||
{
|
||||
struct tegra_dce *d;
|
||||
struct tegra_dce_client_ipc *cl;
|
||||
|
||||
if (!is_client_handle_valid(handle))
|
||||
return -EINVAL;
|
||||
|
||||
cl = &client_handles[client_handle_to_index(handle)];
|
||||
|
||||
if (cl->valid == false)
|
||||
return -EINVAL;
|
||||
|
||||
d = cl->d;
|
||||
d->d_clients[cl->type] = NULL;
|
||||
memset(cl, 0, sizeof(struct tegra_dce_client_ipc));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dce_client_async_event_work(struct work_struct *data)
|
||||
{
|
||||
struct tegra_dce_client_ipc *cl;
|
||||
struct dce_async_work *work = container_of(data, struct dce_async_work,
|
||||
async_event_work);
|
||||
struct tegra_dce *d = work->d;
|
||||
|
||||
cl = d->d_clients[DCE_CLIENT_IPC_TYPE_RM_EVENT];
|
||||
|
||||
dce_client_process_event_ipc(d, cl);
|
||||
atomic_set(&work->in_use, 0);
|
||||
}
|
||||
|
||||
int tegra_dce_register_ipc_client(u32 type,
|
||||
tegra_dce_client_ipc_callback_t callback_fn,
|
||||
void *data, u32 *handlep)
|
||||
{
|
||||
int ret;
|
||||
uint32_t int_type;
|
||||
struct tegra_dce *d = NULL;
|
||||
struct tegra_dce_client_ipc *cl;
|
||||
u32 handle = DCE_CLIENT_IPC_HANDLE_INVALID;
|
||||
|
||||
if (handlep == NULL) {
|
||||
dce_err(d, "Invalid handle pointer");
|
||||
ret = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (type >= DCE_CLIENT_IPC_TYPE_MAX) {
|
||||
dce_err(d, "Failed to retrieve client info for type: [%u]", type);
|
||||
ret = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
int_type = dce_interface_type_map[type];
|
||||
|
||||
d = dce_ipc_get_dce_from_ch(int_type);
|
||||
if (d == NULL) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for bootstrapping to complete before client IPC registration
|
||||
*/
|
||||
#define DCE_IPC_REGISTER_BOOT_WAIT (30U * 1000)
|
||||
ret = DCE_COND_WAIT_INTERRUPTIBLE_TIMEOUT(&d->dce_bootstrap_done,
|
||||
dce_is_bootstrap_done(d),
|
||||
DCE_IPC_REGISTER_BOOT_WAIT);
|
||||
if (ret) {
|
||||
dce_info(d, "dce boot wait failed (%d)\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = dce_client_ipc_handle_alloc(&handle);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
cl = &client_handles[client_handle_to_index(handle)];
|
||||
|
||||
cl->d = d;
|
||||
cl->type = type;
|
||||
cl->data = data;
|
||||
cl->handle = handle;
|
||||
cl->int_type = int_type;
|
||||
cl->callback_fn = callback_fn;
|
||||
atomic_set(&cl->complete, 0);
|
||||
|
||||
ret = dce_cond_init(&cl->recv_wait);
|
||||
if (ret) {
|
||||
dce_err(d, "dce condition initialization failed for int_type: [%u]",
|
||||
int_type);
|
||||
goto out;
|
||||
}
|
||||
|
||||
d->d_clients[type] = cl;
|
||||
|
||||
out:
|
||||
if (ret != 0) {
|
||||
dce_client_ipc_handle_free(handle);
|
||||
handle = DCE_CLIENT_IPC_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
*handlep = handle;
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(tegra_dce_register_ipc_client);
|
||||
|
||||
int tegra_dce_unregister_ipc_client(u32 handle)
|
||||
{
|
||||
struct tegra_dce_client_ipc *cl;
|
||||
|
||||
cl = &client_handles[client_handle_to_index(handle)];
|
||||
dce_cond_destroy(&cl->recv_wait);
|
||||
|
||||
return dce_client_ipc_handle_free(handle);
|
||||
}
|
||||
EXPORT_SYMBOL(tegra_dce_unregister_ipc_client);
|
||||
|
||||
int tegra_dce_client_ipc_send_recv(u32 handle, struct dce_ipc_message *msg)
|
||||
{
|
||||
int ret;
|
||||
struct tegra_dce_client_ipc *cl;
|
||||
|
||||
if (msg == NULL) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cl = dce_client_ipc_lookup_handle(handle);
|
||||
if (cl == NULL) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = dce_ipc_send_message_sync(cl->d, cl->int_type, msg);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(tegra_dce_client_ipc_send_recv);
|
||||
|
||||
int dce_client_init(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t i;
|
||||
struct tegra_dce_async_ipc_info *d_aipc = &d->d_async_ipc;
|
||||
|
||||
d_aipc->async_event_wq =
|
||||
create_singlethread_workqueue("dce-async-ipc-wq");
|
||||
|
||||
for (i = 0; i < DCE_MAX_ASYNC_WORK; i++) {
|
||||
struct dce_async_work *d_work = &d_aipc->work[i];
|
||||
|
||||
INIT_WORK(&d_work->async_event_work,
|
||||
dce_client_async_event_work);
|
||||
d_work->d = d;
|
||||
atomic_set(&d_work->in_use, 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dce_client_deinit(struct tegra_dce *d)
|
||||
{
|
||||
struct tegra_dce_async_ipc_info *d_aipc = &d->d_async_ipc;
|
||||
|
||||
flush_workqueue(d_aipc->async_event_wq);
|
||||
destroy_workqueue(d_aipc->async_event_wq);
|
||||
}
|
||||
|
||||
int dce_client_ipc_wait(struct tegra_dce *d, u32 int_type)
|
||||
{
|
||||
uint32_t type;
|
||||
struct tegra_dce_client_ipc *cl;
|
||||
|
||||
type = dce_client_get_type(int_type);
|
||||
if (type >= DCE_CLIENT_IPC_TYPE_MAX) {
|
||||
dce_err(d, "Failed to retrieve client info for int_type: [%d]",
|
||||
int_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cl = d->d_clients[type];
|
||||
if ((cl == NULL) || (cl->int_type != int_type)) {
|
||||
dce_err(d, "Failed to retrieve client info for int_type: [%d]",
|
||||
int_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
retry_wait:
|
||||
DCE_COND_WAIT_INTERRUPTIBLE(&cl->recv_wait,
|
||||
atomic_read(&cl->complete) == 1);
|
||||
if (atomic_read(&cl->complete) != 1)
|
||||
goto retry_wait;
|
||||
|
||||
atomic_set(&cl->complete, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dce_client_process_event_ipc(struct tegra_dce *d,
|
||||
struct tegra_dce_client_ipc *cl)
|
||||
{
|
||||
void *msg_data = NULL;
|
||||
u32 msg_length;
|
||||
int ret = 0;
|
||||
|
||||
if ((cl == NULL) || (cl->callback_fn == NULL)) {
|
||||
dce_err(d, "Invalid arg tegra_dce_client_ipc");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cl->type != DCE_CLIENT_IPC_TYPE_RM_EVENT) {
|
||||
dce_err(d, "Invalid arg for DCE_CLIENT_IPC_TYPE_RM_EVENT type:[%u]", cl->type);
|
||||
return;
|
||||
}
|
||||
|
||||
msg_data = dce_kzalloc(d, DCE_CLIENT_MAX_IPC_MSG_SIZE, false);
|
||||
if (msg_data == NULL) {
|
||||
dce_err(d, "Could not allocate msg read buffer");
|
||||
goto done;
|
||||
}
|
||||
msg_length = DCE_CLIENT_MAX_IPC_MSG_SIZE;
|
||||
|
||||
while (dce_ipc_is_data_available(d, cl->int_type)) {
|
||||
ret = dce_ipc_read_message(d, cl->int_type, msg_data, msg_length);
|
||||
if (ret) {
|
||||
dce_info(d, "Error in reading DCE msg for ch_type [%d]",
|
||||
cl->int_type);
|
||||
goto done;
|
||||
}
|
||||
|
||||
cl->callback_fn(cl->handle, cl->type, msg_length, msg_data, cl->data);
|
||||
}
|
||||
|
||||
done:
|
||||
if (msg_data)
|
||||
dce_kfree(d, msg_data);
|
||||
}
|
||||
|
||||
static void dce_client_schedule_event_work(struct tegra_dce *d)
|
||||
{
|
||||
struct tegra_dce_async_ipc_info *async_work_info = &d->d_async_ipc;
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < DCE_MAX_ASYNC_WORK; i++) {
|
||||
struct dce_async_work *d_work = &async_work_info->work[i];
|
||||
|
||||
if (atomic_add_unless(&d_work->in_use, 1, 1) > 0) {
|
||||
queue_work(async_work_info->async_event_wq,
|
||||
&d_work->async_event_work);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == DCE_MAX_ASYNC_WORK)
|
||||
dce_err(d, "Failed to schedule Async event Queue Full!");
|
||||
}
|
||||
|
||||
void dce_client_ipc_wakeup(struct tegra_dce *d, u32 ch_type)
|
||||
{
|
||||
uint32_t type;
|
||||
struct tegra_dce_client_ipc *cl;
|
||||
|
||||
type = dce_client_get_type(ch_type);
|
||||
if (type == DCE_CLIENT_IPC_TYPE_MAX) {
|
||||
dce_err(d, "Failed to retrieve client info for ch_type: [%d]",
|
||||
ch_type);
|
||||
return;
|
||||
}
|
||||
|
||||
cl = d->d_clients[type];
|
||||
if ((cl == NULL) || (cl->int_type != ch_type)) {
|
||||
dce_err(d, "Failed to retrieve client info for ch_type: [%d]",
|
||||
ch_type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == DCE_CLIENT_IPC_TYPE_RM_EVENT)
|
||||
return dce_client_schedule_event_work(d);
|
||||
|
||||
atomic_set(&cl->complete, 1);
|
||||
dce_cond_signal_interruptible(&cl->recv_wait);
|
||||
}
|
||||
549
drivers/platform/tegra/dce/dce-debug-perf.c
Normal file
549
drivers/platform/tegra/dce/dce-debug-perf.c
Normal file
@@ -0,0 +1,549 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 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 <linux/errno.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <dce.h>
|
||||
#include <dce-log.h>
|
||||
#include <dce-util-common.h>
|
||||
#include <interface/dce-interface.h>
|
||||
|
||||
#define DCE_PERF_OUTPUT_FORMAT_CSV ((uint32_t)(0U))
|
||||
#define DCE_PERF_OUTPUT_FORMAT_XML ((uint32_t)(1U))
|
||||
|
||||
static uint32_t perf_output_format = DCE_PERF_OUTPUT_FORMAT_CSV;
|
||||
|
||||
ssize_t dbg_dce_perf_stats_stats_fops_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
int ret = 0;
|
||||
bool start_perf;
|
||||
struct dce_ipc_message *msg = NULL;
|
||||
struct dce_admin_ipc_cmd *req_msg;
|
||||
struct tegra_dce *d = ((struct seq_file *)file->private_data)->private;
|
||||
|
||||
ret = kstrtobool_from_user(user_buf, 3ULL, &start_perf);
|
||||
if (ret) {
|
||||
dce_err(d, "Unable to parse start/stop for dce perf stats");
|
||||
goto out;
|
||||
}
|
||||
|
||||
msg = dce_admin_allocate_message(d);
|
||||
if (!msg) {
|
||||
dce_err(d, "IPC msg allocation failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
req_msg = (struct dce_admin_ipc_cmd *)(msg->tx.data);
|
||||
|
||||
/*
|
||||
* Collect All Perfs
|
||||
* Clear previous data and start collecting new perf data
|
||||
*
|
||||
* TODO: Add support to collect specific perf data
|
||||
*/
|
||||
req_msg->args.perf.perf_cmd.enable = DCE_ADMIN_PERF_STATS_ALL;
|
||||
req_msg->args.perf.perf_cmd.clear = DCE_ADMIN_PERF_CLEAR_CLEAR;
|
||||
|
||||
/*
|
||||
* echo "1/y" (kstrtobool true) to start perf data collection
|
||||
* echo "0/n" (kstrtobool false) to stop perf data collection
|
||||
*/
|
||||
ret = dce_admin_send_cmd_set_perf_stat(d, msg, start_perf);
|
||||
if (ret) {
|
||||
dce_err(d, "Failed to Set perf stat\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
dce_debug(d, "DCE perf stats collection %s", start_perf ? "started" : "stopped");
|
||||
|
||||
out:
|
||||
dce_admin_free_message(d, msg);
|
||||
return count;
|
||||
}
|
||||
|
||||
static void dbg_dce_perf_stats_sched_task_xml(struct seq_file *s, struct tegra_dce *d,
|
||||
const struct dce_admin_task_stats *task_stat)
|
||||
{
|
||||
/* Don't print task stats if task name is not set */
|
||||
if (task_stat->name == NULL)
|
||||
return;
|
||||
|
||||
seq_printf(s, "<task><name>%s</name>", task_stat->name);
|
||||
seq_printf(s, "<init>%llu</init><ready>%llu</ready>",
|
||||
task_stat->init, task_stat->ready);
|
||||
seq_printf(s, "<ready_time>%llu</ready_time>",
|
||||
task_stat->ready_time);
|
||||
seq_printf(s, "<dcache_misses>%llu</dcache_misses><instr_exec_count>%llu</instr_exec_count>",
|
||||
task_stat->dcache_misses, task_stat->inst_exec);
|
||||
seq_printf(s, "<mmio_req_count>%llu</mmio_req_count>",
|
||||
task_stat->mmio_req);
|
||||
seq_printf(s, "<stat><name>sleep</name><accumulate>%llu</accumulate>",
|
||||
task_stat->sleep.accumulate);
|
||||
seq_printf(s, "<iterations>%llu</iterations><min>%llu</min><max>%llu</max></stat>",
|
||||
task_stat->sleep.iterations,
|
||||
task_stat->sleep.min,
|
||||
task_stat->sleep.max);
|
||||
seq_printf(s, "<stat><name>run</name><accumulate>%llu</accumulate>",
|
||||
task_stat->run.accumulate);
|
||||
seq_printf(s, "<iterations>%llu</iterations><min>%llu</min><max>%llu</max></stat>",
|
||||
task_stat->run.iterations,
|
||||
task_stat->run.min,
|
||||
task_stat->run.max);
|
||||
seq_printf(s, "<stat><name>run-context</name><accumulate>%llu</accumulate>",
|
||||
task_stat->run_context.accumulate);
|
||||
seq_printf(s, "<iterations>%llu</iterations><min>%llu</min><max>%llu</max></stat>",
|
||||
task_stat->run_context.iterations,
|
||||
task_stat->run_context.min,
|
||||
task_stat->run_context.max);
|
||||
seq_puts(s, "</task>\n");
|
||||
}
|
||||
|
||||
static void dbg_dce_perf_stats_pm_event_xml(struct seq_file *s,
|
||||
const struct dce_admin_pm_event_stats *pm_evt)
|
||||
{
|
||||
seq_printf(s, "<start>%llu</start><end>%llu</end>\n", pm_evt->start, pm_evt->end);
|
||||
seq_printf(s, "<count>%llu</count>\n", pm_evt->count);
|
||||
}
|
||||
|
||||
static void dbg_dce_perf_stats_show_xml(struct seq_file *s, struct tegra_dce *d,
|
||||
struct dce_admin_perf_info *perf)
|
||||
{
|
||||
|
||||
const struct dce_admin_pm_event_stats *pm_evt;
|
||||
const struct dce_admin_sched_stats *sched = &perf->sched;
|
||||
uint32_t i;
|
||||
|
||||
seq_puts(s, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
|
||||
seq_puts(s, "<PerfData>");
|
||||
seq_printf(s, "<tcm_ready>%llu</tcm_ready>\n", perf->tcm_ready);
|
||||
seq_printf(s, "<sched_start>%llu</sched_start>\n", perf->sched_start);
|
||||
seq_printf(s, "<signaled_ready>%llu</signaled_ready>\n", perf->ready_time);
|
||||
|
||||
/*
|
||||
* dCache-misses Perf Data
|
||||
*/
|
||||
pm_evt = &perf->pm_events[DCE_ADMIN_PM_EVT_DCACHE_MISSES];
|
||||
seq_puts(s, "<dcache-misses>\n");
|
||||
dbg_dce_perf_stats_pm_event_xml(s, pm_evt);
|
||||
seq_puts(s, "</dcache-misses>\n");
|
||||
|
||||
/*
|
||||
* instruction execution Perf Data
|
||||
*/
|
||||
pm_evt = &perf->pm_events[DCE_ADMIN_PM_EVT_INSTR_EXEC];
|
||||
seq_puts(s, "<instr-execution>\n");
|
||||
dbg_dce_perf_stats_pm_event_xml(s, pm_evt);
|
||||
seq_puts(s, "</instr-execution>\n");
|
||||
|
||||
/*
|
||||
* instruction execution Perf Data
|
||||
*/
|
||||
pm_evt = &perf->pm_events[DCE_ADMIN_PM_EVT_MEM_REQ];
|
||||
seq_puts(s, "<mmio-request>\n");
|
||||
dbg_dce_perf_stats_pm_event_xml(s, pm_evt);
|
||||
seq_puts(s, "</mmio-request>\n");
|
||||
|
||||
/*
|
||||
* Print Scheduler Perf data and Per task data
|
||||
*/
|
||||
seq_puts(s, "<sched>\n");
|
||||
seq_printf(s, "<start>%llu</start><end>%llu</end>", sched->start, sched->end);
|
||||
seq_printf(s, "<context_switches>%llu</context_switches>\n", sched->context_switches);
|
||||
|
||||
for (i = 0U; i < DCE_ADMIN_PERF_ACTIVE_TASKS_NUM; i += 1U) {
|
||||
dbg_dce_perf_stats_sched_task_xml(s, d,
|
||||
&sched->tasks[i]);
|
||||
}
|
||||
|
||||
seq_puts(s, "</sched>"); //sched perf data done
|
||||
seq_puts(s, "</PerfData>\n");
|
||||
}
|
||||
|
||||
|
||||
static void dbg_dce_perf_stats_sched_task_csv(struct seq_file *s, struct tegra_dce *d,
|
||||
const struct dce_admin_task_stats *task_stat)
|
||||
{
|
||||
/* Don't print if task_name is not set */
|
||||
if (task_stat->name == NULL)
|
||||
return;
|
||||
|
||||
seq_printf(s, "\"%s\",\"%llu\",\"%llu\",\"%llu\",\"%llu\",\"%llu\",\"%llu\",\"sleep\",\"%llu\",\"%llu\",\"%llu\",\"%llu\"\n",
|
||||
task_stat->name, task_stat->init, task_stat->ready,
|
||||
task_stat->ready_time, task_stat->dcache_misses,
|
||||
task_stat->inst_exec, task_stat->mmio_req,
|
||||
task_stat->sleep.accumulate,
|
||||
task_stat->sleep.iterations, task_stat->sleep.min,
|
||||
task_stat->sleep.max);
|
||||
seq_puts(s, "\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"run\",");
|
||||
seq_printf(s, "\"%llu\",\"%llu\",\"%llu\",\"%llu\"\n",
|
||||
task_stat->run.accumulate, task_stat->run.iterations,
|
||||
task_stat->run.min, task_stat->run.max);
|
||||
seq_puts(s, "\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"run-context\",");
|
||||
seq_printf(s, "\"%llu\",\"%llu\",\"%llu\",\"%llu\"\n",
|
||||
task_stat->run_context.accumulate,
|
||||
task_stat->run_context.iterations,
|
||||
task_stat->run_context.min,
|
||||
task_stat->run_context.max);
|
||||
}
|
||||
|
||||
static void dbg_dce_perf_stats_show_csv(struct seq_file *s, struct tegra_dce *d,
|
||||
struct dce_admin_perf_info *perf)
|
||||
{
|
||||
const struct dce_admin_pm_event_stats *pm_evt;
|
||||
const struct dce_admin_sched_stats *sched = &perf->sched;
|
||||
uint32_t i;
|
||||
|
||||
seq_puts(s, "\"tcm-ready\",\"sched-start\",\"signaled-ready\",");
|
||||
seq_puts(s, "\"dcache:start-time\",\"dcache:end-time\",\"dcache:miss_cnt\",");
|
||||
seq_puts(s, "\"inst_exec:start-time\",\"inst_exec:end-time\",\"inst_exec:count\",");
|
||||
seq_puts(s, "\"mmio_req:start-time\",\"mmio_req:end-time\",\"mmio_req:count\",");
|
||||
seq_puts(s, "\"sched:start-time\",\"sched:end-time\",\"sched:context_switches\"\n");
|
||||
seq_printf(s, "\"%llu\",\"%llu\",\"%llu\",", perf->tcm_ready,
|
||||
perf->sched_start, perf->ready_time);
|
||||
|
||||
/*
|
||||
* Print Cache Perf data
|
||||
*/
|
||||
pm_evt = &perf->pm_events[DCE_ADMIN_PM_EVT_DCACHE_MISSES];
|
||||
seq_printf(s, "\"%llu\",\"%llu\",\"%llu\",",
|
||||
pm_evt->start, pm_evt->end, pm_evt->count);
|
||||
|
||||
/*
|
||||
* Print Instruction exec Perf data
|
||||
*/
|
||||
pm_evt = &perf->pm_events[DCE_ADMIN_PM_EVT_INSTR_EXEC];
|
||||
seq_printf(s, "\"%llu\",\"%llu\",\"%llu\",",
|
||||
pm_evt->start, pm_evt->end, pm_evt->count);
|
||||
|
||||
/*
|
||||
* Print Instruction exec Perf data
|
||||
*/
|
||||
pm_evt = &perf->pm_events[DCE_ADMIN_PM_EVT_MEM_REQ];
|
||||
seq_printf(s, "\"%llu\",\"%llu\",\"%llu\",",
|
||||
pm_evt->start, pm_evt->end, pm_evt->count);
|
||||
/*
|
||||
* Print Scheduler Perf data and Per task data
|
||||
*/
|
||||
seq_printf(s, "\"%llu\",\"%llu\",\"%llu\"\n",
|
||||
sched->start, sched->end,
|
||||
sched->context_switches);
|
||||
|
||||
seq_puts(s, "\"sched:task_name\",\"sched:task-init\",\"sched:task-ready\",");
|
||||
seq_puts(s, "\"sched:task-ready-time\",\"sched:task-stat:dcache-misses\",");
|
||||
seq_puts(s, "\"sched:task-stat:instr_exec\",\"sched:task-stat:mem_req\",");
|
||||
seq_puts(s, "\"sched:task-stat:name\",");
|
||||
seq_puts(s, "\"sched:task-stat:accumulate\",\"sched:task-stat:iterations\",");
|
||||
seq_puts(s, "\"sched:task-stat:min\",\"sched:task-stat:max\"\n");
|
||||
for (i = 0U; i < DCE_ADMIN_PERF_ACTIVE_TASKS_NUM; i += 1U) {
|
||||
dbg_dce_perf_stats_sched_task_csv(s, d,
|
||||
&sched->tasks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int dbg_dce_perf_stats_stats_fops_show(struct seq_file *s, void *data)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_ipc_message *msg = NULL;
|
||||
struct dce_admin_ipc_resp *resp_msg;
|
||||
struct dce_admin_perf_info *perf;
|
||||
struct tegra_dce *d = (struct tegra_dce *)s->private;
|
||||
|
||||
msg = dce_admin_allocate_message(d);
|
||||
if (!msg) {
|
||||
dce_err(d, "IPC msg allocation failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = dce_admin_send_cmd_get_perf_stat(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "Failed to Get perf stat\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
resp_msg = (struct dce_admin_ipc_resp *) (msg->rx.data);
|
||||
perf = &resp_msg->args.perf.info.sched_stats;
|
||||
|
||||
if (perf_output_format == DCE_PERF_OUTPUT_FORMAT_CSV)
|
||||
dbg_dce_perf_stats_show_csv(s, d, perf);
|
||||
else
|
||||
dbg_dce_perf_stats_show_xml(s, d, perf);
|
||||
|
||||
out:
|
||||
dce_admin_free_message(d, msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dbg_dce_perf_stats_stats_fops_open(struct inode *inode,
|
||||
struct file *file)
|
||||
{
|
||||
return single_open(file, dbg_dce_perf_stats_stats_fops_show,
|
||||
inode->i_private);
|
||||
}
|
||||
|
||||
/*
|
||||
* Debugfs nodes for displaying a help message about perf stats capture
|
||||
*/
|
||||
static int dbg_dce_perf_stats_help_fops_show(struct seq_file *s, void *data)
|
||||
{
|
||||
/**
|
||||
* Writing
|
||||
* '0' to /sys/kernel/debug/tegra_dce/perf/stats/stats
|
||||
* - Clear the Perf stats data
|
||||
* '1' to /sys/kernel/debug/tegra_dce/perf/stats/stats
|
||||
* - Start the Perf stats data
|
||||
* To capture fresh Perf stats, first clear and Start.
|
||||
*
|
||||
* The result can be printed in csv or xml format
|
||||
*
|
||||
* '0' to /sys/kernel/debug/tegra_dce/perf/format
|
||||
* - Data is collected in CSV format
|
||||
* '1' to /sys/kernel/debug/tegra_dce/perf/format
|
||||
* - Data is collected in XML format
|
||||
* Default is set for CSV
|
||||
*
|
||||
* cat /sys/kernel/debug/tegra_dce/perf/stats/stats
|
||||
* - get the perf data in selected format
|
||||
*
|
||||
*/
|
||||
seq_printf(s, "DCE Perf Capture\n"
|
||||
"----------------------\n"
|
||||
" echo '0' > perf/stats/stats : Clear perf data\n"
|
||||
" cat perf/stats/stats : get perf data in selected format\n"
|
||||
" echo <0/1> > perf/format : get data in CSV/XML format\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dbg_dce_perf_stats_help_fops_open(struct inode *inode,
|
||||
struct file *file)
|
||||
{
|
||||
return single_open(file, dbg_dce_perf_stats_help_fops_show,
|
||||
inode->i_private);
|
||||
}
|
||||
|
||||
ssize_t dbg_dce_perf_format_fops_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 format;
|
||||
struct tegra_dce *d = ((struct seq_file *)file->private_data)->private;
|
||||
|
||||
ret = kstrtou32_from_user(user_buf, count, 10, &format);
|
||||
if (ret) {
|
||||
dce_err(d, "Invalid format!");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (format == DCE_PERF_OUTPUT_FORMAT_CSV)
|
||||
perf_output_format = DCE_PERF_OUTPUT_FORMAT_CSV;
|
||||
else if (format == DCE_PERF_OUTPUT_FORMAT_XML)
|
||||
perf_output_format = DCE_PERF_OUTPUT_FORMAT_XML;
|
||||
else
|
||||
dce_err(d, "Invalid format [%u]!", format);
|
||||
|
||||
done:
|
||||
return count;
|
||||
}
|
||||
|
||||
static int dbg_dce_perf_format_fops_show(struct seq_file *s, void *data)
|
||||
{
|
||||
seq_printf(s, "Supported Formats\n"
|
||||
"----------------------\n"
|
||||
"CSV:0 XML:1\n"
|
||||
"Current format:%s\n",
|
||||
(perf_output_format == DCE_PERF_OUTPUT_FORMAT_CSV) ? "CSV" : "XML");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dbg_dce_perf_format_fops_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, dbg_dce_perf_format_fops_show,
|
||||
inode->i_private);
|
||||
}
|
||||
|
||||
/*
|
||||
* Debugfs nodes for displaying a help message about perf stats capture
|
||||
*/
|
||||
static int dbg_dce_perf_events_help_fops_show(struct seq_file *s, void *data)
|
||||
{
|
||||
/**
|
||||
* Writing
|
||||
* '0' to /sys/kernel/debug/tegra_dce/perf/events/events
|
||||
* - Clear the Perf Events data
|
||||
* 'Bit masked value' to /kernel/debug/tegra_dce/perf/events/events
|
||||
* - Enable an event for the Perf Events data capture.
|
||||
* Clear bit mask if the event perf is not needed to be captured.
|
||||
*
|
||||
* The result can be printed in csv or xml format
|
||||
*
|
||||
* '0' to /sys/kernel/debug/tegra_dce/perf/format
|
||||
* - Data is collected in CSV format
|
||||
* '1' to /sys/kernel/debug/tegra_dce/perf/format
|
||||
* - Data is collected in XML format
|
||||
* Default is set for CSV
|
||||
*
|
||||
* cat /sys/kernel/debug/tegra_dce/perf/events/events
|
||||
* - get the perf event data in selected format
|
||||
* - shows event name/ accumulated time/ iterations happened
|
||||
* - min and max time taken to run an event iteration
|
||||
*/
|
||||
seq_printf(s, "DCE Perf Events Capture\n"
|
||||
"----------------------\n"
|
||||
" echo '0' > perf/events/events: Clear perf events data\n"
|
||||
" echo 'bit masked value' > perf/events/events: Enable perf event capture\n"
|
||||
" cat perf/events/events: get perf events data in selected format\n"
|
||||
" echo <0/1> > perf/format: get data in CSV/XML format\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dbg_dce_perf_events_help_fops_open(struct inode *inode,
|
||||
struct file *file)
|
||||
{
|
||||
return single_open(file, dbg_dce_perf_events_help_fops_show,
|
||||
inode->i_private);
|
||||
}
|
||||
|
||||
ssize_t dbg_dce_perf_events_events_fops_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
int ret = 0;
|
||||
uint32_t events;
|
||||
struct dce_ipc_message *msg = NULL;
|
||||
struct dce_admin_ipc_cmd *req_msg;
|
||||
struct tegra_dce *d = ((struct seq_file *)file->private_data)->private;
|
||||
|
||||
/*
|
||||
* Writing "0/n" will clear the events
|
||||
* Write Bit Masked value to enable events
|
||||
*/
|
||||
ret = kstrtou32_from_user(user_buf, count, 0, &events);
|
||||
if (ret) {
|
||||
dce_err(d, "Unable to parse for event perf stats");
|
||||
goto out;
|
||||
}
|
||||
|
||||
msg = dce_admin_allocate_message(d);
|
||||
if (!msg) {
|
||||
dce_err(d, "IPC msg allocation failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
req_msg = (struct dce_admin_ipc_cmd *)(msg->tx.data);
|
||||
|
||||
if (events == 0x0U) {
|
||||
// Clear event
|
||||
req_msg->args.perf.event_cmd.clear = DCE_ADMIN_EVENT_CLEAR_CLEAR;
|
||||
} else {
|
||||
// Disable all Events if enable : 0x80000000
|
||||
// Elase enable only Bit masked events
|
||||
req_msg->args.perf.event_cmd.clear = DCE_ADMIN_EVENT_CLEAR_RETAIN;
|
||||
req_msg->args.perf.event_cmd.enable = events;
|
||||
}
|
||||
|
||||
ret = dce_admin_send_cmd_clear_perf_events(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "Failed to Clear perf events\n");
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
dce_admin_free_message(d, msg);
|
||||
return count;
|
||||
}
|
||||
|
||||
static void dbg_dce_perf_events_show_csv(struct seq_file *s, struct tegra_dce *d,
|
||||
const struct dce_admin_event_info *events)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
seq_puts(s, "\"Evt Name\",\"accumulate\",\"iterations\",\"min\",\"max\"\n");
|
||||
|
||||
for (i = 0; i < DCE_ADMIN_NUM_EVENTS; i++) {
|
||||
if (events->events[i].name == NULL)
|
||||
continue;
|
||||
|
||||
seq_printf(s, "\"%s\",\"%llu\",\"%llu\",\"%llu\",\"%llu\"\n",
|
||||
events->events[i].name, events->events[i].event.accumulate,
|
||||
events->events[i].event.iterations, events->events[i].event.min,
|
||||
events->events[i].event.max);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void dbg_dce_perf_events_show_xml(struct seq_file *s, struct tegra_dce *d,
|
||||
const struct dce_admin_event_info *events)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
seq_puts(s, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
|
||||
seq_puts(s, "<EventsPerfData>");
|
||||
|
||||
for (i = 0; i < DCE_ADMIN_NUM_EVENTS; i++) {
|
||||
if (events->events[i].name == NULL)
|
||||
continue;
|
||||
|
||||
seq_printf(s, "<name>%s</name>\n", events->events[i].name);
|
||||
seq_printf(s, "<accumulate>%llu</accumulate>\n",
|
||||
events->events[i].event.accumulate);
|
||||
seq_printf(s, "<iterations>%llu</iterations>\n",
|
||||
events->events[i].event.iterations);
|
||||
seq_printf(s, "<min>%llu</min>\n", events->events[i].event.min);
|
||||
seq_printf(s, "<max>%llu</max>\n", events->events[i].event.max);
|
||||
}
|
||||
|
||||
seq_puts(s, "</EventsPerfData>\n");
|
||||
}
|
||||
|
||||
static int dbg_dce_perf_events_events_fops_show(struct seq_file *s, void *data)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_ipc_message *msg = NULL;
|
||||
struct dce_admin_ipc_resp *resp_msg;
|
||||
struct dce_admin_event_info *events;
|
||||
struct tegra_dce *d = (struct tegra_dce *)s->private;
|
||||
|
||||
msg = dce_admin_allocate_message(d);
|
||||
if (!msg) {
|
||||
dce_err(d, "IPC msg allocation failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = dce_admin_send_cmd_get_perf_events(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "Failed to Get perf stat\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
resp_msg = (struct dce_admin_ipc_resp *) (msg->rx.data);
|
||||
events = &resp_msg->args.perf.info.events_stats;
|
||||
|
||||
if (perf_output_format == DCE_PERF_OUTPUT_FORMAT_CSV)
|
||||
dbg_dce_perf_events_show_csv(s, d, events);
|
||||
else
|
||||
dbg_dce_perf_events_show_xml(s, d, events);
|
||||
|
||||
out:
|
||||
dce_admin_free_message(d, msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dbg_dce_perf_events_events_fops_open(struct inode *inode,
|
||||
struct file *file)
|
||||
{
|
||||
return single_open(file, dbg_dce_perf_events_events_fops_show,
|
||||
inode->i_private);
|
||||
}
|
||||
845
drivers/platform/tegra/dce/dce-debug.c
Normal file
845
drivers/platform/tegra/dce/dce-debug.c
Normal file
@@ -0,0 +1,845 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2019-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 <linux/errno.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <dce.h>
|
||||
#include <dce-log.h>
|
||||
#include <dce-util-common.h>
|
||||
#include <dce-debug-perf.h>
|
||||
#include <interface/dce-interface.h>
|
||||
#include <interface/dce-core-interface-errors.h>
|
||||
|
||||
/**
|
||||
* dbg_dce_load_fw - loads the fw to DRAM.
|
||||
*
|
||||
* @d : Pointer to dce struct
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
static int dbg_dce_load_fw(struct tegra_dce *d)
|
||||
{
|
||||
const char *name = dce_get_fw_name(d);
|
||||
|
||||
d->fw_data = dce_request_firmware(d, name);
|
||||
if (!d->fw_data) {
|
||||
dce_err(d, "FW Request Failed");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
dce_set_load_fw_status(d, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dbg_dce_config_ast - Configures the ast and sets the status.
|
||||
*
|
||||
* @d : Pointer to dce struct
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dbg_dce_config_ast(struct tegra_dce *d)
|
||||
{
|
||||
dce_config_ast(d);
|
||||
dce_set_ast_config_status(d, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* dbg_dce_reset_dce - Configures the evp in DCE cluster
|
||||
* and brings dce out of reset.
|
||||
*
|
||||
* @d : Pointer to dce struct
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
static int dbg_dce_reset_dce(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
|
||||
ret = dce_reset_dce(d);
|
||||
if (ret) {
|
||||
dce_err(d, "DCE Reset Failed");
|
||||
return ret;
|
||||
}
|
||||
dce_set_dce_reset_status(d, true);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* dbg_dce_boot_dce - loads the fw and configures other dce cluster
|
||||
* elements for bringing dce out of reset.
|
||||
*
|
||||
* @d : Pointer to dce struct
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
static int dbg_dce_boot_dce(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
|
||||
ret = dbg_dce_load_fw(d);
|
||||
if (ret) {
|
||||
dce_err(d, "DCE Load FW Failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dbg_dce_config_ast(d);
|
||||
|
||||
ret = dbg_dce_reset_dce(d);
|
||||
|
||||
if (ret)
|
||||
dce_err(d, "DCE Reset Failed");
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static ssize_t dbg_dce_load_fw_read(struct file *file,
|
||||
char __user *user_buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
char buf[3];
|
||||
struct tegra_dce *d = file->private_data;
|
||||
|
||||
if (d->load_complete)
|
||||
buf[0] = 'Y';
|
||||
else
|
||||
buf[0] = 'N';
|
||||
buf[1] = '\n';
|
||||
buf[2] = 0x00;
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
|
||||
}
|
||||
|
||||
static ssize_t dbg_dce_load_fw_write(struct file *file,
|
||||
const char __user *user_buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
int ret = 0;
|
||||
char buf[32];
|
||||
int buf_size;
|
||||
bool bv;
|
||||
struct tegra_dce *d = file->private_data;
|
||||
|
||||
buf_size = min(count, (sizeof(buf)-1));
|
||||
if (copy_from_user(buf, user_buf, buf_size))
|
||||
return -EFAULT;
|
||||
|
||||
if (strtobool(buf, &bv) == 0) {
|
||||
if (bv == true) {
|
||||
ret = dbg_dce_load_fw(d);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations load_firmware_fops = {
|
||||
.open = simple_open,
|
||||
.read = dbg_dce_load_fw_read,
|
||||
.write = dbg_dce_load_fw_write,
|
||||
};
|
||||
|
||||
static ssize_t dbg_dce_config_ast_read(struct file *file,
|
||||
char __user *user_buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
char buf[3];
|
||||
struct tegra_dce *d = file->private_data;
|
||||
|
||||
if (d->ast_config_complete)
|
||||
buf[0] = 'Y';
|
||||
else
|
||||
buf[0] = 'N';
|
||||
buf[1] = '\n';
|
||||
buf[2] = 0x00;
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
|
||||
}
|
||||
|
||||
static ssize_t dbg_dce_config_ast_write(struct file *file,
|
||||
const char __user *user_buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
char buf[32];
|
||||
int buf_size;
|
||||
bool bv;
|
||||
struct tegra_dce *d = file->private_data;
|
||||
|
||||
buf_size = min(count, (sizeof(buf)-1));
|
||||
if (copy_from_user(buf, user_buf, buf_size))
|
||||
return -EFAULT;
|
||||
|
||||
if (strtobool(buf, &bv) == 0) {
|
||||
if (bv == true)
|
||||
dbg_dce_config_ast(d);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations config_ast_fops = {
|
||||
.open = simple_open,
|
||||
.read = dbg_dce_config_ast_read,
|
||||
.write = dbg_dce_config_ast_write,
|
||||
};
|
||||
|
||||
static ssize_t dbg_dce_reset_dce_fops_read(struct file *file,
|
||||
char __user *user_buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
char buf[3];
|
||||
struct tegra_dce *d = file->private_data;
|
||||
|
||||
if (d->reset_complete)
|
||||
buf[0] = 'Y';
|
||||
else
|
||||
buf[0] = 'N';
|
||||
buf[1] = '\n';
|
||||
buf[2] = 0x00;
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
|
||||
}
|
||||
|
||||
static ssize_t dbg_dce_reset_dce_fops_write(struct file *file,
|
||||
const char __user *user_buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
int ret = 0;
|
||||
char buf[32];
|
||||
int buf_size;
|
||||
bool bv;
|
||||
struct tegra_dce *d = file->private_data;
|
||||
|
||||
buf_size = min(count, (sizeof(buf)-1));
|
||||
if (copy_from_user(buf, user_buf, buf_size))
|
||||
return -EFAULT;
|
||||
|
||||
if (strtobool(buf, &bv) == 0) {
|
||||
if (bv == true) {
|
||||
ret = dbg_dce_reset_dce(d);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations reset_dce_fops = {
|
||||
.open = simple_open,
|
||||
.read = dbg_dce_reset_dce_fops_read,
|
||||
.write = dbg_dce_reset_dce_fops_write,
|
||||
};
|
||||
|
||||
static ssize_t dbg_dce_admin_echo_fops_write(struct file *file,
|
||||
const char __user *user_buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
int ret = 0;
|
||||
char buf[32];
|
||||
int buf_size;
|
||||
u32 i, echo_count;
|
||||
struct dce_ipc_message *msg = NULL;
|
||||
struct dce_admin_ipc_cmd *req_msg;
|
||||
struct dce_admin_ipc_resp *resp_msg;
|
||||
struct tegra_dce *d = file->private_data;
|
||||
|
||||
buf_size = min(count, (sizeof(buf)-1));
|
||||
ret = kstrtou32_from_user(user_buf, buf_size, 10, &echo_count);
|
||||
if (ret) {
|
||||
dce_err(d, "Admin msg count out of range");
|
||||
goto out;
|
||||
}
|
||||
|
||||
msg = dce_admin_allocate_message(d);
|
||||
if (!msg) {
|
||||
dce_err(d, "IPC msg allocation failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
req_msg = (struct dce_admin_ipc_cmd *)(msg->tx.data);
|
||||
resp_msg = (struct dce_admin_ipc_resp *) (msg->rx.data);
|
||||
|
||||
dce_info(d, "Requested %u echo messages", echo_count);
|
||||
|
||||
for (i = 0; i < echo_count; i++) {
|
||||
u32 resp;
|
||||
|
||||
req_msg->args.echo.data = i;
|
||||
ret = dce_admin_send_cmd_echo(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "Admin msg failed for seq No : %u", i);
|
||||
goto out;
|
||||
}
|
||||
|
||||
resp = resp_msg->args.echo.data;
|
||||
|
||||
if (i == resp) {
|
||||
dce_info(d, "Received Response:%u for request:%u",
|
||||
resp, i);
|
||||
} else {
|
||||
dce_err(d, "Invalid response, expected:%u received:%u",
|
||||
i, resp);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (msg)
|
||||
dce_admin_free_message(d, msg);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations admin_echo_fops = {
|
||||
.open = simple_open,
|
||||
.write = dbg_dce_admin_echo_fops_write,
|
||||
};
|
||||
|
||||
/*
|
||||
* Debugfs nodes for displaying a help message about tests required by external
|
||||
* clients (ex: MODS)
|
||||
*/
|
||||
static int dbg_dce_tests_external_help_fops_show(struct seq_file *s, void *data)
|
||||
{
|
||||
/* TODO: Add test description? */
|
||||
seq_printf(s, "DCE External Test List\n"
|
||||
"----------------------\n"
|
||||
" - Test #0: MODS ALU Test\n"
|
||||
" - Test #1: MODS DMA Test\n");
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int dbg_dce_tests_external_help_fops_open(struct inode *inode,
|
||||
struct file *file)
|
||||
{
|
||||
return single_open(file, dbg_dce_tests_external_help_fops_show,
|
||||
inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations tests_external_help_fops = {
|
||||
.open = dbg_dce_tests_external_help_fops_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
/* Get status of last external client test run */
|
||||
static ssize_t dbg_dce_tests_external_status_fops_read(struct file *file,
|
||||
char __user *user_buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct tegra_dce *d = file->private_data;
|
||||
struct dce_device *d_dev = dce_device_from_dce(d);
|
||||
char buf[15];
|
||||
ssize_t bytes_printed;
|
||||
|
||||
bytes_printed = snprintf(buf, 15, "%d\n", d_dev->ext_test_status);
|
||||
if (bytes_printed < 0) {
|
||||
dce_err(d, "Unable to return external test status");
|
||||
buf[0] = '\0';
|
||||
bytes_printed = 0;
|
||||
}
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, bytes_printed);
|
||||
}
|
||||
|
||||
static const struct file_operations tests_external_status_fops = {
|
||||
.open = simple_open,
|
||||
.read = dbg_dce_tests_external_status_fops_read,
|
||||
};
|
||||
|
||||
/* Run an external client test */
|
||||
static ssize_t dbg_dce_tests_external_run_fops_write(struct file *file,
|
||||
const char __user *user_buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 test;
|
||||
struct dce_ipc_message *msg = NULL;
|
||||
struct dce_admin_ipc_cmd *req_msg = NULL;
|
||||
struct dce_admin_ipc_resp *resp_msg = NULL;
|
||||
struct tegra_dce *d = file->private_data;
|
||||
struct dce_device *d_dev = dce_device_from_dce(d);
|
||||
|
||||
ret = kstrtou32_from_user(user_buf, count, 10, &test);
|
||||
if (ret) {
|
||||
dce_err(d, "Invalid test number!");
|
||||
d_dev->ext_test_status = DCE_ERR_CORE_NOT_FOUND;
|
||||
return -EINVAL;
|
||||
}
|
||||
switch (test) {
|
||||
case DCE_ADMIN_EXT_TEST_ALU:
|
||||
dce_info(d, "Running ALU test");
|
||||
break;
|
||||
|
||||
case DCE_ADMIN_EXT_TEST_DMA:
|
||||
dce_info(d, "Running DMA test");
|
||||
break;
|
||||
|
||||
default:
|
||||
dce_err(d, "Test(%u) not found! Check help node for valid test IDs.",
|
||||
test);
|
||||
d_dev->ext_test_status = DCE_ERR_CORE_NOT_FOUND;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
msg = dce_admin_allocate_message(d);
|
||||
if (!msg) {
|
||||
dce_err(d, "IPC msg allocation failed");
|
||||
d_dev->ext_test_status = DCE_ERR_CORE_OTHER;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
req_msg = (struct dce_admin_ipc_cmd *)(msg->tx.data);
|
||||
resp_msg = (struct dce_admin_ipc_resp *) (msg->rx.data);
|
||||
|
||||
req_msg->args.ext_test.test = test;
|
||||
ret = dce_admin_send_cmd_ext_test(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "Admin msg failed");
|
||||
d_dev->ext_test_status = DCE_ERR_CORE_IPC_IVC_ERR;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (resp_msg->error == DCE_ERR_CORE_SUCCESS)
|
||||
dce_info(d, "Test passed!");
|
||||
else if (resp_msg->error == DCE_ERR_CORE_NOT_IMPLEMENTED)
|
||||
dce_err(d, "Test not implemented!");
|
||||
else
|
||||
dce_err(d, "Test failed(%d)!", (int32_t)resp_msg->error);
|
||||
d_dev->ext_test_status = resp_msg->error;
|
||||
|
||||
exit:
|
||||
if (msg)
|
||||
dce_admin_free_message(d, msg);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations tests_external_run_fops = {
|
||||
.open = simple_open,
|
||||
.write = dbg_dce_tests_external_run_fops_write,
|
||||
};
|
||||
|
||||
static ssize_t dbg_dce_boot_dce_fops_read(struct file *file,
|
||||
char __user *user_buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
char buf[3];
|
||||
struct tegra_dce *d = file->private_data;
|
||||
|
||||
if (d->ast_config_complete &&
|
||||
d->reset_complete && d->load_complete)
|
||||
buf[0] = 'Y';
|
||||
else
|
||||
buf[0] = 'N';
|
||||
buf[1] = '\n';
|
||||
buf[2] = 0x00;
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
|
||||
}
|
||||
|
||||
static ssize_t dbg_dce_boot_dce_fops_write(struct file *file,
|
||||
const char __user *user_buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
int ret = 0;
|
||||
char buf[32];
|
||||
int buf_size;
|
||||
bool bv;
|
||||
struct tegra_dce *d = file->private_data;
|
||||
|
||||
buf_size = min(count, (sizeof(buf)-1));
|
||||
if (copy_from_user(buf, user_buf, buf_size))
|
||||
return -EFAULT;
|
||||
|
||||
if (strtobool(buf, &bv) == 0) {
|
||||
if (bv == true) {
|
||||
ret = dbg_dce_boot_dce(d);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations boot_dce_fops = {
|
||||
.open = simple_open,
|
||||
.read = dbg_dce_boot_dce_fops_read,
|
||||
.write = dbg_dce_boot_dce_fops_write,
|
||||
};
|
||||
|
||||
static ssize_t dbg_dce_boot_status_fops_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
u8 fsb;
|
||||
char buf[32];
|
||||
u32 last_status;
|
||||
ssize_t len = 0;
|
||||
unsigned long bitmap;
|
||||
struct tegra_dce *d = file->private_data;
|
||||
u32 boot_status = d->boot_status;
|
||||
hsp_sema_t ss = dce_ss_get_state(d, DCE_BOOT_SEMA);
|
||||
|
||||
if (ss & DCE_BOOT_COMPLETE)
|
||||
goto core_boot_done;
|
||||
|
||||
/* Clear BOOT_COMPLETE bit and bits set by OS */
|
||||
ss &= ~(DCE_OS_BITMASK | DCE_BOOT_COMPLETE);
|
||||
bitmap = ss;
|
||||
|
||||
fsb = find_first_bit(&bitmap, 32U);
|
||||
if (fsb > 31U) {
|
||||
dce_info(d, "dce-fw boot not started yet");
|
||||
goto core_boot_done;
|
||||
}
|
||||
|
||||
last_status = DCE_BIT(fsb);
|
||||
|
||||
switch (last_status) {
|
||||
case DCE_HALTED:
|
||||
strcpy(buf, "DCE_HALTED");
|
||||
break;
|
||||
case DCE_BOOT_TCM_COPY:
|
||||
strcpy(buf, "TCM_COPY");
|
||||
break;
|
||||
case DCE_BOOT_HW_INIT:
|
||||
strcpy(buf, "HW_INIT");
|
||||
break;
|
||||
case DCE_BOOT_MPU_INIT:
|
||||
strcpy(buf, "MPU_INIT:");
|
||||
break;
|
||||
case DCE_BOOT_CACHE_INIT:
|
||||
strcpy(buf, "CACHE_INIT");
|
||||
break;
|
||||
case DCE_BOOT_R5_INIT:
|
||||
strcpy(buf, "R5_INIT");
|
||||
break;
|
||||
case DCE_BOOT_DRIVER_INIT:
|
||||
strcpy(buf, "DRIVER_INIT");
|
||||
break;
|
||||
case DCE_BOOT_MAIN_STARTED:
|
||||
strcpy(buf, "MAIN_STARTED");
|
||||
break;
|
||||
case DCE_BOOT_TASK_INIT_START:
|
||||
strcpy(buf, "TASK_INIT_STARTED");
|
||||
break;
|
||||
case DCE_BOOT_TASK_INIT_DONE:
|
||||
strcpy(buf, "TASK_INIT_DONE");
|
||||
break;
|
||||
default:
|
||||
strcpy(buf, "STATUS_UNKNOWN");
|
||||
break;
|
||||
}
|
||||
goto done;
|
||||
|
||||
core_boot_done:
|
||||
/* Clear DCE_STATUS_FAILED bit get actual failure reason*/
|
||||
boot_status &= ~DCE_STATUS_FAILED;
|
||||
bitmap = boot_status;
|
||||
last_status = DCE_BIT(find_first_bit(&bitmap, 32));
|
||||
|
||||
switch (last_status) {
|
||||
case DCE_FW_SUSPENDED:
|
||||
strcpy(buf, "DCE_FW_SUSPENDED");
|
||||
break;
|
||||
case DCE_FW_BOOT_DONE:
|
||||
strcpy(buf, "DCE_FW_BOOT_DONE");
|
||||
break;
|
||||
case DCE_FW_ADMIN_SEQ_DONE:
|
||||
strcpy(buf, "DCE_FW_ADMIN_SEQ_DONE");
|
||||
break;
|
||||
case DCE_FW_ADMIN_SEQ_FAILED:
|
||||
strcpy(buf, "DCE_FW_ADMIN_SEQ_FAILED");
|
||||
break;
|
||||
case DCE_FW_ADMIN_SEQ_START:
|
||||
strcpy(buf, "DCE_FW_ADMIN_SEQ_STARTED");
|
||||
break;
|
||||
case DCE_FW_BOOTSTRAP_DONE:
|
||||
strcpy(buf, "DCE_FW_BOOTSTRAP_DONE");
|
||||
break;
|
||||
case DCE_FW_BOOTSTRAP_FAILED:
|
||||
strcpy(buf, "DCE_FW_BOOTSTRAP_FAILED");
|
||||
break;
|
||||
case DCE_FW_BOOTSTRAP_START:
|
||||
strcpy(buf, "DCE_FW_BOOTSTRAP_STARTED");
|
||||
break;
|
||||
case DCE_FW_EARLY_BOOT_FAILED:
|
||||
strcpy(buf, "DCE_FW_EARLY_BOOT_FAILED");
|
||||
break;
|
||||
case DCE_FW_EARLY_BOOT_DONE:
|
||||
strcpy(buf, "DCE_FW_EARLY_BOOT_DONE");
|
||||
break;
|
||||
case DCE_AST_CONFIG_DONE:
|
||||
strcpy(buf, "DCE_AST_CONFIG_DONE");
|
||||
break;
|
||||
case DCE_AST_CONFIG_START:
|
||||
strcpy(buf, "DCE_AST_CONFIG_STARTED");
|
||||
break;
|
||||
case DCE_EARLY_INIT_DONE:
|
||||
strcpy(buf, "DCE_EARLY_INIT_DONE");
|
||||
break;
|
||||
case DCE_EARLY_INIT_FAILED:
|
||||
strcpy(buf, "DCE_EARLY_INIT_FAILED");
|
||||
break;
|
||||
case DCE_EARLY_INIT_START:
|
||||
strcpy(buf, "DCE_EARLY_INIT_STARTED");
|
||||
break;
|
||||
default:
|
||||
strcpy(buf, "STATUS_UNKNOWN");
|
||||
}
|
||||
|
||||
done:
|
||||
len = strlen(buf);
|
||||
buf[len] = '\0';
|
||||
dce_info(d, "boot status:%s status_val:0x%x\n", buf, d->boot_status);
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len + 1);
|
||||
}
|
||||
|
||||
static const struct file_operations boot_status_fops = {
|
||||
.open = simple_open,
|
||||
.read = dbg_dce_boot_status_fops_read,
|
||||
};
|
||||
|
||||
static const struct file_operations perf_format_fops = {
|
||||
.open = dbg_dce_perf_format_fops_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.write = dbg_dce_perf_format_fops_write,
|
||||
};
|
||||
|
||||
static const struct file_operations perf_stats_stats_fops = {
|
||||
.open = dbg_dce_perf_stats_stats_fops_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.write = dbg_dce_perf_stats_stats_fops_write,
|
||||
};
|
||||
|
||||
static const struct file_operations perf_stats_help_fops = {
|
||||
.open = dbg_dce_perf_stats_help_fops_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static const struct file_operations perf_events_events_fops = {
|
||||
.open = dbg_dce_perf_events_events_fops_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.write = dbg_dce_perf_events_events_fops_write,
|
||||
};
|
||||
|
||||
static const struct file_operations perf_events_help_fops = {
|
||||
.open = dbg_dce_perf_events_help_fops_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
void dce_remove_debug(struct tegra_dce *d)
|
||||
{
|
||||
struct dce_device *d_dev = dce_device_from_dce(d);
|
||||
|
||||
debugfs_remove(d_dev->debugfs);
|
||||
|
||||
d_dev->debugfs = NULL;
|
||||
}
|
||||
|
||||
static int dump_hsp_regs_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
u8 i = 0;
|
||||
struct tegra_dce *d = s->private;
|
||||
|
||||
/**
|
||||
* Dump Boot Semaphore Value
|
||||
*/
|
||||
dce_info(d, "DCE_BOOT_SEMA : 0x%x",
|
||||
dce_ss_get_state(d, DCE_BOOT_SEMA));
|
||||
|
||||
/**
|
||||
* Dump Shared Mailboxes Values
|
||||
*/
|
||||
dce_info(d, "DCE_MBOX_FROM_DCE_RM : 0x%x",
|
||||
dce_smb_read(d, DCE_MBOX_FROM_DCE_RM));
|
||||
dce_info(d, "DCE_MBOX_TO_DCE_RM: 0x%x",
|
||||
dce_smb_read(d, DCE_MBOX_TO_DCE_RM));
|
||||
dce_info(d, "DCE_MBOX_FROM_DCE_RM_EVENT_NOTIFY: 0x%x",
|
||||
dce_smb_read(d, DCE_MBOX_FROM_DCE_RM_EVENT_NOTIFY));
|
||||
dce_info(d, "DCE_MBOX_TO_DCE_RM_EVENT_NOTIFY: 0x%x",
|
||||
dce_smb_read(d, DCE_MBOX_TO_DCE_RM_EVENT_NOTIFY));
|
||||
dce_info(d, "DCE_MBOX_FROM_DCE_ADMIN: 0x%x",
|
||||
dce_smb_read(d, DCE_MBOX_FROM_DCE_ADMIN));
|
||||
dce_info(d, "DCE_MBOX_BOOT_CMD: 0x%x",
|
||||
dce_smb_read(d, DCE_MBOX_BOOT_CMD));
|
||||
dce_info(d, "DCE_MBOX_IRQ: 0x%x",
|
||||
dce_smb_read(d, DCE_MBOX_IRQ));
|
||||
|
||||
/**
|
||||
* Dump HSP IE registers Values
|
||||
*/
|
||||
|
||||
#define DCE_MAX_IE_REGS 5U
|
||||
for (i = 0; i < DCE_MAX_IE_REGS; i++)
|
||||
dce_info(d, "DCE_HSP_IE_%d : 0x%x", i, dce_hsp_ie_read(d, i));
|
||||
#undef DCE_MAX_IE_REGS
|
||||
|
||||
/**
|
||||
* Dump HSP IE registers Values
|
||||
*/
|
||||
#define DCE_MAX_SM_FULL_REGS 8U
|
||||
for (i = 0; i < DCE_MAX_SM_FULL_REGS; i++) {
|
||||
dce_info(d, "DCE_HSP_SM_FULL_%d : 0x%x", i,
|
||||
dce_smb_read_full_ie(d, i));
|
||||
}
|
||||
#undef DCE_MAX_SM_FULL_REGS
|
||||
|
||||
dce_info(d, "DCE_HSP_IR : 0x%x",
|
||||
dce_hsp_ir_read(d));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dump_hsp_regs_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, dump_hsp_regs_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations dump_hsp_regs_fops = {
|
||||
.open = dump_hsp_regs_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_init_debug - Initializes the debug features of dce
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
void dce_init_debug(struct tegra_dce *d)
|
||||
{
|
||||
struct dentry *retval;
|
||||
struct device *dev = dev_from_dce(d);
|
||||
struct dce_device *d_dev = dce_device_from_dce(d);
|
||||
struct dentry *debugfs_dir = NULL;
|
||||
struct dentry *perf_debugfs_dir = NULL;
|
||||
|
||||
d_dev->debugfs = debugfs_create_dir("tegra_dce", NULL);
|
||||
if (!d_dev->debugfs)
|
||||
return;
|
||||
|
||||
retval = debugfs_create_file("load_fw", 0444,
|
||||
d_dev->debugfs, d, &load_firmware_fops);
|
||||
if (!retval)
|
||||
goto err_handle;
|
||||
|
||||
retval = debugfs_create_file("config_ast", 0444,
|
||||
d_dev->debugfs, d, &config_ast_fops);
|
||||
if (!retval)
|
||||
goto err_handle;
|
||||
|
||||
retval = debugfs_create_file("reset", 0444,
|
||||
d_dev->debugfs, d, &reset_dce_fops);
|
||||
if (!retval)
|
||||
goto err_handle;
|
||||
|
||||
retval = debugfs_create_file("boot", 0444,
|
||||
d_dev->debugfs, d, &boot_dce_fops);
|
||||
if (!retval)
|
||||
goto err_handle;
|
||||
|
||||
retval = debugfs_create_file("admin_echo", 0444,
|
||||
d_dev->debugfs, d, &admin_echo_fops);
|
||||
if (!retval)
|
||||
goto err_handle;
|
||||
|
||||
retval = debugfs_create_file("boot_status", 0444,
|
||||
d_dev->debugfs, d, &boot_status_fops);
|
||||
if (!retval)
|
||||
goto err_handle;
|
||||
|
||||
perf_debugfs_dir = debugfs_create_dir("perf", d_dev->debugfs);
|
||||
if (!perf_debugfs_dir)
|
||||
goto err_handle;
|
||||
|
||||
retval = debugfs_create_file("format", 0644,
|
||||
perf_debugfs_dir, d, &perf_format_fops);
|
||||
if (!retval)
|
||||
goto err_handle;
|
||||
|
||||
debugfs_dir = debugfs_create_dir("stats", perf_debugfs_dir);
|
||||
if (!debugfs_dir)
|
||||
goto err_handle;
|
||||
|
||||
retval = debugfs_create_file("stats", 0644,
|
||||
debugfs_dir, d, &perf_stats_stats_fops);
|
||||
if (!retval)
|
||||
goto err_handle;
|
||||
|
||||
retval = debugfs_create_file("help", 0444,
|
||||
debugfs_dir, d, &perf_stats_help_fops);
|
||||
if (!retval)
|
||||
goto err_handle;
|
||||
|
||||
debugfs_dir = debugfs_create_dir("events", perf_debugfs_dir);
|
||||
if (!debugfs_dir)
|
||||
goto err_handle;
|
||||
|
||||
retval = debugfs_create_file("events", 0644,
|
||||
debugfs_dir, d, &perf_events_events_fops);
|
||||
if (!retval)
|
||||
goto err_handle;
|
||||
|
||||
retval = debugfs_create_file("help", 0444,
|
||||
debugfs_dir, d, &perf_events_help_fops);
|
||||
if (!retval)
|
||||
goto err_handle;
|
||||
|
||||
retval = debugfs_create_file("dump_hsp_regs", 0444,
|
||||
d_dev->debugfs, d, &dump_hsp_regs_fops);
|
||||
if (!retval)
|
||||
goto err_handle;
|
||||
|
||||
/* Tests */
|
||||
debugfs_dir = debugfs_create_dir("tests", d_dev->debugfs);
|
||||
if (!debugfs_dir)
|
||||
goto err_handle;
|
||||
debugfs_dir = debugfs_create_dir("external", debugfs_dir);
|
||||
if (!debugfs_dir)
|
||||
goto err_handle;
|
||||
retval = debugfs_create_file("help", 0444,
|
||||
debugfs_dir, d, &tests_external_help_fops);
|
||||
if (!retval)
|
||||
goto err_handle;
|
||||
retval = debugfs_create_file("run", 0220,
|
||||
debugfs_dir, d, &tests_external_run_fops);
|
||||
if (!retval)
|
||||
goto err_handle;
|
||||
retval = debugfs_create_file("status", 0444,
|
||||
debugfs_dir, d, &tests_external_status_fops);
|
||||
if (!retval)
|
||||
goto err_handle;
|
||||
|
||||
return;
|
||||
|
||||
err_handle:
|
||||
dev_err(dev, "could not create debugfs\n");
|
||||
dce_remove_debug(d);
|
||||
}
|
||||
534
drivers/platform/tegra/dce/dce-fsm.c
Normal file
534
drivers/platform/tegra/dce/dce-fsm.c
Normal file
@@ -0,0 +1,534 @@
|
||||
/*
|
||||
* 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>
|
||||
#include <dce-util-common.h>
|
||||
|
||||
struct dce_event_process_struct {
|
||||
enum dce_fsm_event_id_type event;
|
||||
int (*fsm_event_handle)(struct tegra_dce *d, void *params);
|
||||
};
|
||||
|
||||
/*
|
||||
* Please update FSM design Document, whenever updating below event table
|
||||
*/
|
||||
static struct dce_event_process_struct event_process_table[] = {
|
||||
{
|
||||
.event = EVENT_ID_DCE_FSM_START,
|
||||
.fsm_event_handle = dce_handle_fsm_start_event,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_BOOT_COMPLETE_REQUESTED,
|
||||
.fsm_event_handle = dce_handle_boot_complete_requested_event,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_BOOT_COMPLETE_RECEIVED,
|
||||
.fsm_event_handle = dce_handle_boot_complete_received_event,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_BOOT_CMD_MSG_REQUESTED,
|
||||
.fsm_event_handle = dce_handle_boot_cmd_requested_event,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_BOOT_CMD_MSG_RECEIVED,
|
||||
.fsm_event_handle = dce_handle_boot_cmd_received_event,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_ADMIN_IPC_MSG_REQUESTED,
|
||||
.fsm_event_handle = dce_admin_handle_ipc_requested_event,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_ADMIN_IPC_MSG_RECEIVED,
|
||||
.fsm_event_handle = dce_admin_handle_ipc_received_event,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_SC7_ENTER_REQUESTED,
|
||||
.fsm_event_handle = dce_pm_handle_sc7_enter_requested_event,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_SC7_ENTERED_RECEIVED,
|
||||
.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,
|
||||
.fsm_event_handle = dce_handle_event_stub,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_LOG_READY_RECEIVED,
|
||||
.fsm_event_handle = dce_handle_event_stub,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_ABORT_RECEIVED,
|
||||
.fsm_event_handle = dce_handle_event_stub,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_CRASH_LOG_RECEIVED,
|
||||
.fsm_event_handle = dce_handle_event_stub,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_LOG_OVERFLOW_RECEIVED,
|
||||
.fsm_event_handle = dce_handle_event_stub,
|
||||
},
|
||||
{
|
||||
.event = EVENT_ID_DCE_FSM_STOP,
|
||||
.fsm_event_handle = dce_handle_event_stub,
|
||||
},
|
||||
};
|
||||
|
||||
#define DCE_MAX_EVENTS_IDS (sizeof(event_process_table) / \
|
||||
sizeof(struct dce_event_process_struct))
|
||||
|
||||
/**
|
||||
* dce_handle_fsm_start_event - Callback handler function for FSM_START event.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @params : callback params
|
||||
*
|
||||
* Return : 0 if successful else error code
|
||||
*/
|
||||
int dce_handle_fsm_start_event(struct tegra_dce *d, void *params)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_handle_event_stub - Stub callback handler function.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @params : callback params
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
int dce_handle_event_stub(struct tegra_dce *d, void *params)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_fsm_set_state - Set the FSM state based on event
|
||||
*
|
||||
* This Function is called with Mutex held.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @event : Event for which FSM state need to be set
|
||||
*
|
||||
* Return : void
|
||||
*
|
||||
* Please update FSM design Document, whenever updating below event states
|
||||
*/
|
||||
static void
|
||||
dce_fsm_set_state(struct tegra_dce *d,
|
||||
enum dce_fsm_event_id_type event)
|
||||
{
|
||||
struct dce_fsm_info *fsm = &d->fsm_info;
|
||||
|
||||
switch (event) {
|
||||
case EVENT_ID_DCE_FSM_START:
|
||||
fsm->c_state = STATE_DCE_FSM_IDLE;
|
||||
fsm->requested_ipcs = 0;
|
||||
break;
|
||||
|
||||
case EVENT_ID_DCE_BOOT_COMPLETE_REQUESTED:
|
||||
fsm->c_state = STATE_DCE_BOOT_WAIT;
|
||||
fsm->requested_ipcs |= DCE_BIT(DCE_WAIT_BOOT_COMPLETE);
|
||||
break;
|
||||
|
||||
case EVENT_ID_DCE_BOOT_COMPLETE_RECEIVED:
|
||||
fsm->c_state = STATE_DCE_FSM_IDLE;
|
||||
fsm->requested_ipcs &= ~DCE_BIT(DCE_WAIT_BOOT_COMPLETE);
|
||||
break;
|
||||
|
||||
case EVENT_ID_DCE_BOOT_CMD_MSG_REQUESTED:
|
||||
fsm->c_state = STATE_DCE_BOOTCMD_WFI;
|
||||
fsm->requested_ipcs |= DCE_BIT(DCE_WAIT_BOOT_CMD);
|
||||
break;
|
||||
|
||||
case EVENT_ID_DCE_BOOT_CMD_MSG_RECEIVED:
|
||||
fsm->c_state = STATE_DCE_FSM_IDLE;
|
||||
fsm->requested_ipcs &= ~DCE_BIT(DCE_WAIT_BOOT_CMD);
|
||||
break;
|
||||
|
||||
case EVENT_ID_DCE_ADMIN_IPC_MSG_REQUESTED:
|
||||
fsm->c_state = STATE_DCE_ADMIN_WFI;
|
||||
fsm->requested_ipcs |= DCE_BIT(DCE_WAIT_ADMIN_IPC);
|
||||
break;
|
||||
|
||||
case EVENT_ID_DCE_ADMIN_IPC_MSG_RECEIVED:
|
||||
fsm->c_state = STATE_DCE_FSM_IDLE;
|
||||
fsm->requested_ipcs &= ~DCE_BIT(DCE_WAIT_ADMIN_IPC);
|
||||
break;
|
||||
|
||||
case EVENT_ID_DCE_SC7_ENTER_REQUESTED:
|
||||
fsm->c_state = STATE_DCE_SC7_ENTER_WFI;
|
||||
fsm->requested_ipcs |= DCE_BIT(DCE_WAIT_SC7_ENTER);
|
||||
break;
|
||||
|
||||
case EVENT_ID_DCE_SC7_ENTERED_RECEIVED:
|
||||
fsm->c_state = STATE_DCE_SC7_ENTERED;
|
||||
fsm->requested_ipcs &= ~DCE_BIT(DCE_WAIT_SC7_ENTER);
|
||||
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:
|
||||
fsm->c_state = STATE_DCE_LOG_READY_WFI;
|
||||
fsm->requested_ipcs |= DCE_BIT(DCE_WAIT_LOG);
|
||||
break;
|
||||
|
||||
case EVENT_ID_DCE_LOG_READY_RECEIVED:
|
||||
fsm->c_state = STATE_DCE_FSM_IDLE;
|
||||
fsm->requested_ipcs &= ~DCE_BIT(DCE_WAIT_LOG);
|
||||
break;
|
||||
|
||||
case EVENT_ID_DCE_FSM_STOP:
|
||||
fsm->c_state = STATE_DCE_INVALID;
|
||||
break;
|
||||
|
||||
case EVENT_ID_DCE_ABORT_RECEIVED:
|
||||
case EVENT_ID_DCE_CRASH_LOG_RECEIVED:
|
||||
case EVENT_ID_DCE_LOG_OVERFLOW_RECEIVED:
|
||||
dce_debug(d, "DCE Abort received");
|
||||
fsm->c_state = STATE_DCE_ABORT;
|
||||
/*
|
||||
* TODO: error handling
|
||||
* wake-up any waiting process avoid kernel watchdog
|
||||
* trigger and crash
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
dce_err(d, "INVALID EVENT [%d]", event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* dce_fsm_validate_event - Validate event agaist current FSM state
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
* @event : Posted FSM event
|
||||
*
|
||||
* @return : ESUCCESS if event valid else error code
|
||||
*
|
||||
* Please update FSM design Document, whenever updating below event validation
|
||||
*/
|
||||
static int
|
||||
dce_fsm_validate_event(struct tegra_dce *d,
|
||||
enum dce_fsm_event_id_type event)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_fsm_info *fsm = &d->fsm_info;
|
||||
enum dce_fsm_state curr_state;
|
||||
|
||||
if (event > EVENT_ID_DCE_FSM_STOP) {
|
||||
dce_err(d, "Invalid event received [%d]\n", event);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// Should we check This??
|
||||
if (fsm->initialized == false) {
|
||||
dce_err(d, "FSM is not initialized yet\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
curr_state = fsm->c_state;
|
||||
dce_debug(d, "Called for event [%d], curr_state:[%d]", event, curr_state);
|
||||
switch (curr_state) {
|
||||
case STATE_DCE_INVALID:
|
||||
switch (event) {
|
||||
case EVENT_ID_DCE_FSM_START:
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
dce_err(d, "Invalid event received [%d] state:[%d]\n",
|
||||
event, curr_state);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_DCE_FSM_IDLE:
|
||||
switch (event) {
|
||||
case EVENT_ID_DCE_BOOT_COMPLETE_RECEIVED:
|
||||
case EVENT_ID_DCE_BOOT_CMD_MSG_RECEIVED:
|
||||
case EVENT_ID_DCE_ADMIN_IPC_MSG_RECEIVED:
|
||||
case EVENT_ID_DCE_SC7_ENTERED_RECEIVED:
|
||||
case EVENT_ID_DCE_LOG_READY_RECEIVED:
|
||||
case EVENT_ID_DCE_FSM_START:
|
||||
dce_err(d, "Invalid event received [%d] state:[%d]\n",
|
||||
event, curr_state);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
default:
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_DCE_BOOT_WAIT:
|
||||
switch (event) {
|
||||
case EVENT_ID_DCE_BOOT_COMPLETE_RECEIVED:
|
||||
case EVENT_ID_DCE_ABORT_RECEIVED:
|
||||
case EVENT_ID_DCE_CRASH_LOG_RECEIVED:
|
||||
case EVENT_ID_DCE_SC7_ENTER_REQUESTED: // TODO: Do we need this here
|
||||
case EVENT_ID_DCE_LOG_OVERFLOW_RECEIVED:
|
||||
case EVENT_ID_DCE_FSM_STOP:
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
dce_err(d, "Invalid event received [%d] state:[%d]\n",
|
||||
event, curr_state);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_DCE_BOOTCMD_WFI:
|
||||
switch (event) {
|
||||
case EVENT_ID_DCE_BOOT_CMD_MSG_RECEIVED:
|
||||
case EVENT_ID_DCE_ABORT_RECEIVED:
|
||||
case EVENT_ID_DCE_CRASH_LOG_RECEIVED:
|
||||
case EVENT_ID_DCE_SC7_ENTER_REQUESTED:
|
||||
case EVENT_ID_DCE_LOG_OVERFLOW_RECEIVED:
|
||||
case EVENT_ID_DCE_FSM_STOP:
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
dce_err(d, "Invalid event received [%d] state:[%d]\n",
|
||||
event, curr_state);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_DCE_ADMIN_WFI:
|
||||
switch (event) {
|
||||
case EVENT_ID_DCE_ADMIN_IPC_MSG_RECEIVED:
|
||||
case EVENT_ID_DCE_ABORT_RECEIVED:
|
||||
case EVENT_ID_DCE_CRASH_LOG_RECEIVED:
|
||||
case EVENT_ID_DCE_SC7_ENTER_REQUESTED:
|
||||
case EVENT_ID_DCE_LOG_OVERFLOW_RECEIVED:
|
||||
case EVENT_ID_DCE_FSM_STOP:
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
dce_err(d, "Invalid event received [%d] state:[%d]\n",
|
||||
event, curr_state);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_DCE_SC7_ENTER_WFI:
|
||||
switch (event) {
|
||||
case EVENT_ID_DCE_SC7_ENTERED_RECEIVED:
|
||||
case EVENT_ID_DCE_ABORT_RECEIVED:
|
||||
case EVENT_ID_DCE_CRASH_LOG_RECEIVED:
|
||||
case EVENT_ID_DCE_LOG_OVERFLOW_RECEIVED:
|
||||
case EVENT_ID_DCE_FSM_STOP:
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
dce_err(d, "Invalid event received [%d] state:[%d]\n",
|
||||
event, curr_state);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_DCE_LOG_READY_WFI:
|
||||
switch (event) {
|
||||
case EVENT_ID_DCE_LOG_READY_RECEIVED:
|
||||
case EVENT_ID_DCE_ABORT_RECEIVED:
|
||||
case EVENT_ID_DCE_CRASH_LOG_RECEIVED:
|
||||
case EVENT_ID_DCE_SC7_ENTER_REQUESTED:
|
||||
case EVENT_ID_DCE_LOG_OVERFLOW_RECEIVED:
|
||||
case EVENT_ID_DCE_FSM_STOP:
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
dce_err(d, "Invalid event received [%d] state:[%d]\n",
|
||||
event, curr_state);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_DCE_SC7_ENTERED:
|
||||
switch (event) {
|
||||
case EVENT_ID_DCE_SC7_EXIT_RECEIVED:
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
dce_err(d, "Invalid event received [%d] state:[%d]\n",
|
||||
event, curr_state);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dce_err(d, "Invalid state:[%d] event received [%d]\n", curr_state,
|
||||
event);
|
||||
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
dce_err(d, "dce event handling failed for event[%d] curr state [%d]",
|
||||
event, curr_state);
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* dce_fsm_get_event_index : Get index of event in event_process_table
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @event : event for which index is requested
|
||||
* @return : index of event in event_process_table or DCE_MAX_EVENTS_IDS
|
||||
*/
|
||||
static u32
|
||||
dce_fsm_get_event_index(struct tegra_dce *d,
|
||||
enum dce_fsm_event_id_type event)
|
||||
{
|
||||
u32 id;
|
||||
|
||||
for (id = 0; id < DCE_MAX_EVENTS_IDS; id++) {
|
||||
struct dce_event_process_struct *e =
|
||||
&event_process_table[id];
|
||||
|
||||
if (e->event == event)
|
||||
break;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_fsm_post - Post event to FSM
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @event : Event for which FSM state need to be set.
|
||||
* @data : Event specific data to pass to the callback function.
|
||||
*
|
||||
* Return : 0 if successful else error code.
|
||||
*/
|
||||
int dce_fsm_post_event(struct tegra_dce *d,
|
||||
enum dce_fsm_event_id_type event,
|
||||
void *data)
|
||||
{
|
||||
u32 id;
|
||||
int ret = 0;
|
||||
enum dce_fsm_state prev_state;
|
||||
struct dce_fsm_info *fsm = &d->fsm_info;
|
||||
|
||||
dce_mutex_lock(&fsm->lock);
|
||||
|
||||
ret = dce_fsm_validate_event(d, event);
|
||||
if (ret) {
|
||||
dce_mutex_unlock(&fsm->lock);
|
||||
goto out;
|
||||
}
|
||||
|
||||
prev_state = fsm->c_state;
|
||||
dce_fsm_set_state(d, event);
|
||||
dce_mutex_unlock(&fsm->lock);
|
||||
|
||||
/*
|
||||
* call callback function with mutex unlocked
|
||||
*/
|
||||
id = dce_fsm_get_event_index(d, event);
|
||||
if ((id < DCE_MAX_EVENTS_IDS) &&
|
||||
(event_process_table[id].fsm_event_handle != NULL)) {
|
||||
ret = event_process_table[id].fsm_event_handle(d, data);
|
||||
if (ret) {
|
||||
dce_mutex_lock(&fsm->lock);
|
||||
dce_err(d, "Callback failed: Resetting state old:new [%d:%d]",
|
||||
prev_state, fsm->c_state);
|
||||
fsm->c_state = prev_state;
|
||||
dce_mutex_unlock(&fsm->lock);
|
||||
}
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_fsm_start - Schedule a work to start the FSM
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : void.
|
||||
*/
|
||||
void dce_fsm_start(struct tegra_dce *d)
|
||||
{
|
||||
dce_schedule_work(&d->dce_bootstrap_work);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_fsm_stop - Post dce_fsm_stop event
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : void.
|
||||
*/
|
||||
void dce_fsm_stop(struct tegra_dce *d)
|
||||
{
|
||||
dce_fsm_post_event(d, EVENT_ID_DCE_FSM_STOP, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_fsm_init - Init the FSM
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : 0 if successful else error code.
|
||||
*/
|
||||
int dce_fsm_init(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_fsm_info *fsm = &d->fsm_info;
|
||||
|
||||
fsm->c_state = STATE_DCE_INVALID;
|
||||
ret = dce_mutex_init(&fsm->lock);
|
||||
if (ret) {
|
||||
dce_err(d, "dce mutex initialization failed for FSM");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dce_mutex_lock(&fsm->lock);
|
||||
fsm->d = d;
|
||||
fsm->initialized = true;
|
||||
dce_mutex_unlock(&fsm->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_fsm_deinit - DeInit the FSM
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
void dce_fsm_deinit(struct tegra_dce *d)
|
||||
{
|
||||
struct dce_fsm_info *fsm = &d->fsm_info;
|
||||
|
||||
dce_mutex_lock(&fsm->lock);
|
||||
fsm->initialized = false;
|
||||
dce_mutex_unlock(&fsm->lock);
|
||||
|
||||
dce_mutex_destroy(&fsm->lock);
|
||||
}
|
||||
279
drivers/platform/tegra/dce/dce-hsp-smb.c
Normal file
279
drivers/platform/tegra/dce/dce-hsp-smb.c
Normal file
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2022, NVIDIA CORPORATION. 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>
|
||||
#include <dce-log.h>
|
||||
#include <dce-util-common.h>
|
||||
|
||||
#define DCE_MAX_NO_SMB 8
|
||||
#define DCE_MAX_HSP_IE 8
|
||||
|
||||
/**
|
||||
* smb_regs is a 2D array of read-only pointers to a function returning u32.
|
||||
*
|
||||
* Array of functions that retrun base addresses of shared maiboxes registers
|
||||
* in DCE cluster based on the mailbox id and HSP id.
|
||||
*/
|
||||
__weak u32 (*const smb_regs[DCE_MAX_HSP][DCE_MAX_NO_SMB])(void) = {
|
||||
{
|
||||
hsp_sm0_r,
|
||||
hsp_sm1_r,
|
||||
hsp_sm2_r,
|
||||
hsp_sm3_r,
|
||||
hsp_sm4_r,
|
||||
hsp_sm5_r,
|
||||
hsp_sm6_r,
|
||||
hsp_sm7_r,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* smb_full_ie_regs is a 2D array of read-only pointers to a function
|
||||
* returning u32.
|
||||
*
|
||||
* Array of functions that retrun base addresses of full IE for shared
|
||||
* maiboxes registers in DCE cluster based on the mailbox id and HSP id.
|
||||
*/
|
||||
__weak u32 (*const smb_full_ie_regs[DCE_MAX_HSP][DCE_MAX_NO_SMB])(void) = {
|
||||
{
|
||||
hsp_sm0_full_int_ie_r,
|
||||
hsp_sm1_full_int_ie_r,
|
||||
hsp_sm2_full_int_ie_r,
|
||||
hsp_sm3_full_int_ie_r,
|
||||
hsp_sm4_full_int_ie_r,
|
||||
hsp_sm5_full_int_ie_r,
|
||||
hsp_sm6_full_int_ie_r,
|
||||
hsp_sm7_full_int_ie_r,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* smb_empty_ie_regs is a 2D array of read-only pointers to a function
|
||||
* returning u32.
|
||||
*
|
||||
* Array of functions that retrun base addresses of empty IE for shared
|
||||
* maiboxes registers in DCE cluster based on the mailbox id and HSP id.
|
||||
*/
|
||||
__weak u32 (*const smb_empty_ie_regs[DCE_MAX_HSP][DCE_MAX_NO_SMB])(void) = {
|
||||
{
|
||||
hsp_sm0_empty_int_ie_r,
|
||||
hsp_sm1_empty_int_ie_r,
|
||||
hsp_sm2_empty_int_ie_r,
|
||||
hsp_sm3_empty_int_ie_r,
|
||||
hsp_sm4_empty_int_ie_r,
|
||||
hsp_sm5_empty_int_ie_r,
|
||||
hsp_sm6_empty_int_ie_r,
|
||||
hsp_sm7_empty_int_ie_r,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_smb_set - Set an u32 value to smb_#n in the DCE Cluster
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @val : val to set.
|
||||
* @id : Shared Mailbox Id.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
void dce_smb_set(struct tegra_dce *d, u32 val, u8 id)
|
||||
{
|
||||
u32 hsp = d->hsp_id;
|
||||
|
||||
if (id >= DCE_MAX_NO_SMB || hsp >= DCE_MAX_HSP) {
|
||||
dce_err(d, "Invalid Shared Mailbox ID:%u or hsp:%u", id, hsp);
|
||||
return;
|
||||
}
|
||||
|
||||
dce_writel(d, smb_regs[hsp][id](), val);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_smb_set_full_ie - Set an u32 value to smb_#n in the DCE Cluster
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @en : enable if true and disable if false
|
||||
* @id : Shared Mailbox Id.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
void dce_smb_set_full_ie(struct tegra_dce *d, bool en, u8 id)
|
||||
{
|
||||
u32 val = en ? 1U : 0U;
|
||||
u32 hsp = d->hsp_id;
|
||||
|
||||
if (id >= DCE_MAX_NO_SMB || hsp >= DCE_MAX_HSP) {
|
||||
dce_err(d, "Invalid Shared Mailbox ID:%u or hsp:%u", id, hsp);
|
||||
return;
|
||||
}
|
||||
|
||||
dce_writel(d, smb_full_ie_regs[hsp][id](), val);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_smb_read_full_ie - Set an u32 value to smb_#n in the DCE Cluster
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @id : Shared Mailbox Id.
|
||||
*
|
||||
* Return : u32 register value
|
||||
*/
|
||||
u32 dce_smb_read_full_ie(struct tegra_dce *d, u8 id)
|
||||
{
|
||||
u32 hsp = d->hsp_id;
|
||||
|
||||
if (id >= DCE_MAX_NO_SMB || hsp >= DCE_MAX_HSP) {
|
||||
dce_err(d, "Invalid Shared Mailbox ID:%u or hsp:%u", id, hsp);
|
||||
return 0xffffffff; /* TODO : Add DCE Error Numbers */
|
||||
}
|
||||
|
||||
return dce_readl(d, smb_full_ie_regs[hsp][id]());
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_smb_enable_empty_ie - Set an u32 value to smb_#n in the DCE Cluster
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @en : enable if true and disable if false
|
||||
* @id : Shared Mailbox Id.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
void dce_smb_set_empty_ie(struct tegra_dce *d, bool en, u8 id)
|
||||
{
|
||||
u32 val = en ? 1U : 0U;
|
||||
u32 hsp = d->hsp_id;
|
||||
|
||||
if (id >= DCE_MAX_NO_SMB || hsp >= DCE_MAX_HSP) {
|
||||
dce_err(d, "Invalid Shared Mailbox ID:%u or hsp:%u", id, hsp);
|
||||
return;
|
||||
}
|
||||
|
||||
dce_writel(d, smb_empty_ie_regs[hsp][id](), val);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_smb_read - Read the u32 value from smb_#n in the DCE Cluster
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @id : Shared Mailbox Id.
|
||||
*
|
||||
* Return : actual value if successful, 0xffffffff for errors scenarios
|
||||
*/
|
||||
u32 dce_smb_read(struct tegra_dce *d, u8 id)
|
||||
{
|
||||
u32 hsp = d->hsp_id;
|
||||
|
||||
if (id >= DCE_MAX_NO_SMB || hsp >= DCE_MAX_HSP) {
|
||||
dce_err(d, "Invalid Shared Mailbox ID:%u or hsp:%u", id, hsp);
|
||||
return 0xffffffff; /* TODO : Add DCE Error Numbers */
|
||||
}
|
||||
|
||||
return dce_readl(d, smb_regs[hsp][id]());
|
||||
}
|
||||
|
||||
/**
|
||||
* hsp_int_ie_regs is a 2D array of read-only pointers to a
|
||||
* function returning u32.
|
||||
*
|
||||
* Array of functions that retrun base addresses of hsp IE
|
||||
* regs in DCE cluster based on the id.
|
||||
*/
|
||||
__weak u32 (*const hsp_int_ie_regs[DCE_MAX_HSP][DCE_MAX_HSP_IE])(void) = {
|
||||
{
|
||||
hsp_int_ie0_r,
|
||||
hsp_int_ie1_r,
|
||||
hsp_int_ie2_r,
|
||||
hsp_int_ie3_r,
|
||||
hsp_int_ie4_r,
|
||||
hsp_int_ie5_r,
|
||||
hsp_int_ie6_r,
|
||||
hsp_int_ie7_r,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* hsp_int_ie_regs is a 1D array of read-only pointers to a
|
||||
* function returning u32.
|
||||
*
|
||||
* Array of functions that retrun addresses of hsp IR
|
||||
* regs in DCE cluster based on the id.
|
||||
*/
|
||||
__weak u32 (*const hsp_int_ir_regs[DCE_MAX_HSP])(void) = {
|
||||
|
||||
hsp_int_ir_r,
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_hsp_ie_read - Read the u32 value from hsp_int_ie#n
|
||||
* in the DCE Cluster
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @id : Shared IE Id.
|
||||
*
|
||||
* Return : actual value if successful, 0xffffffff for errors scenarios
|
||||
*/
|
||||
u32 dce_hsp_ie_read(struct tegra_dce *d, u8 id)
|
||||
{
|
||||
u32 hsp = d->hsp_id;
|
||||
|
||||
if (id >= DCE_MAX_HSP_IE || hsp >= DCE_MAX_HSP) {
|
||||
dce_err(d, "Invalid Shared HSP IE ID:%u or hsp:%u", id, hsp);
|
||||
return 0xffffffff; /* TODO : Add DCE Error Numbers */
|
||||
}
|
||||
|
||||
return dce_readl(d, hsp_int_ie_regs[hsp][id]());
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_hsp_ie_write - Read the u32 value from hsp_int_ie#n
|
||||
* in the DCE Cluster
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @val : Value to be written
|
||||
* @id : Shared IE Id.
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
void dce_hsp_ie_write(struct tegra_dce *d, u32 val, u8 id)
|
||||
{
|
||||
u32 hsp = d->hsp_id;
|
||||
|
||||
if (id >= DCE_MAX_HSP_IE || hsp >= DCE_MAX_HSP) {
|
||||
dce_err(d, "Invalid Shared HSP IE ID:%u or hsp:%u", id, hsp);
|
||||
return;
|
||||
}
|
||||
|
||||
dce_writel(d, hsp_int_ie_regs[hsp][id](),
|
||||
val | dce_readl(d, hsp_int_ie_regs[hsp][id]()));
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_hsp_ir_read - Read the u32 value from hsp_int_ir
|
||||
* in the DCE Cluster
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : actual value if successful, 0xffffffff for errors scenarios
|
||||
*/
|
||||
u32 dce_hsp_ir_read(struct tegra_dce *d)
|
||||
{
|
||||
u32 hsp = d->hsp_id;
|
||||
|
||||
if (hsp >= DCE_MAX_HSP) {
|
||||
dce_err(d, "Invalid HSP ID:%u", hsp);
|
||||
return 0xffffffff; /* TODO : Add DCE Error Numbers */
|
||||
}
|
||||
|
||||
return dce_readl(d, hsp_int_ir_regs[hsp]());
|
||||
}
|
||||
151
drivers/platform/tegra/dce/dce-hsp-ss.c
Normal file
151
drivers/platform/tegra/dce/dce-hsp-ss.c
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2022, NVIDIA CORPORATION. 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>
|
||||
#include <dce-log.h>
|
||||
#include <dce-util-common.h>
|
||||
|
||||
#define DCE_MAX_NO_SS 4
|
||||
|
||||
/**
|
||||
* ss_set_regs is a 2D array of read-only pointers to a function returning u32.
|
||||
*
|
||||
* Array of functions that retrun base addresses of shared semaphores set
|
||||
* registers in DCE cluster based on the semaphore id and HSP id.
|
||||
*/
|
||||
__weak u32 (*const ss_set_regs[DCE_MAX_HSP][DCE_MAX_NO_SS])(void) = {
|
||||
{
|
||||
hsp_ss0_set_r,
|
||||
hsp_ss1_set_r,
|
||||
hsp_ss2_set_r,
|
||||
hsp_ss3_set_r,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* ss_clear_regs is a 2D array of read-only pointers to a function
|
||||
* returning u32.
|
||||
*
|
||||
* Array of functions that retrun base addresses of shared semaphores clear
|
||||
* registers in DCE cluster based on the semaphore id and HSP id.
|
||||
*/
|
||||
__weak u32 (*const ss_clear_regs[DCE_MAX_HSP][DCE_MAX_NO_SS])(void) = {
|
||||
{
|
||||
hsp_ss0_clr_r,
|
||||
hsp_ss1_clr_r,
|
||||
hsp_ss2_clr_r,
|
||||
hsp_ss3_clr_r,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* ss_state_regs is a 2D array of read-only pointers to a function
|
||||
* returning u32.
|
||||
*
|
||||
* Array of functions that retrun base addresses of shared semaphores state
|
||||
* registers in DCE cluster based on the semaphore id and HSP id.
|
||||
*/
|
||||
__weak u32 (*const ss_state_regs[DCE_MAX_HSP][DCE_MAX_NO_SS])(void) = {
|
||||
{
|
||||
hsp_ss0_state_r,
|
||||
hsp_ss1_state_r,
|
||||
hsp_ss2_state_r,
|
||||
hsp_ss3_state_r,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_ss_get_state - Get the state of ss_#n in the DCE Cluster
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @id : Shared Semaphore Id.
|
||||
*
|
||||
* Return : u32
|
||||
*/
|
||||
u32 dce_ss_get_state(struct tegra_dce *d, u8 id)
|
||||
{
|
||||
u32 hsp = d->hsp_id;
|
||||
|
||||
return dce_readl(d, ss_state_regs[hsp][id]());
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_ss_set - Set an u32 value to ss_#n in the DCE Cluster
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @bpos : bit to be set.
|
||||
* @id : Shared Semaphore Id.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
void dce_ss_set(struct tegra_dce *d, u8 bpos, u8 id)
|
||||
{
|
||||
unsigned long val = 0U;
|
||||
u32 hsp = d->hsp_id;
|
||||
|
||||
if (hsp >= DCE_MAX_HSP || id >= DCE_MAX_NO_SS) {
|
||||
dce_err(d, "Invalid HSP ID:%u OR SS ID:%u", hsp, id);
|
||||
return;
|
||||
}
|
||||
|
||||
val = dce_ss_get_state(d, id);
|
||||
|
||||
/**
|
||||
* Debug info. please remove
|
||||
*/
|
||||
dce_info(d, "Current Value in SS#%d : %lx", id, val);
|
||||
|
||||
/**
|
||||
* TODO :Use DCE_INSERT here.
|
||||
*/
|
||||
dce_bitmap_set(&val, bpos, 1);
|
||||
|
||||
/**
|
||||
* Debug info. please remove
|
||||
*/
|
||||
dce_info(d, "Value after bitmap operation : %lx", val);
|
||||
|
||||
dce_writel(d, ss_set_regs[hsp][id](), (u32)val);
|
||||
|
||||
/**
|
||||
* Debug info. please remove
|
||||
*/
|
||||
val = dce_ss_get_state(d, id);
|
||||
dce_info(d, "Current Value in SS#%d : %lx", id, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_ss_clear - Clear a bit in ss_#n in the DCE Cluster
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @bpos : bit to be cleared.
|
||||
* @id : Shared Semaphore Id.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
void dce_ss_clear(struct tegra_dce *d, u8 bpos, u8 id)
|
||||
{
|
||||
unsigned long val;
|
||||
u32 hsp = d->hsp_id;
|
||||
|
||||
if (hsp >= DCE_MAX_HSP || id >= DCE_MAX_NO_SS) {
|
||||
dce_err(d, "Invalid HSP ID:%u OR SS ID:%u", hsp, id);
|
||||
return;
|
||||
}
|
||||
|
||||
val = dce_ss_get_state(d, id);
|
||||
|
||||
dce_bitmap_set(&val, bpos, 1);
|
||||
|
||||
dce_writel(d, ss_clear_regs[hsp][id](), val);
|
||||
}
|
||||
106
drivers/platform/tegra/dce/dce-init-deinit.c
Normal file
106
drivers/platform/tegra/dce/dce-init-deinit.c
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2019-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>
|
||||
#include <dce-util-common.h>
|
||||
|
||||
/**
|
||||
* dce_driver_init - Initializes the various sw components
|
||||
* and few hw elements dce.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : 0 if successful.
|
||||
*/
|
||||
int dce_driver_init(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/**
|
||||
* Set dce boot satus to false
|
||||
*/
|
||||
dce_set_boot_complete(d, false);
|
||||
|
||||
ret = dce_boot_interface_init(d);
|
||||
if (ret) {
|
||||
dce_err(d, "dce boot interface init failed");
|
||||
goto err_boot_interface_init;
|
||||
}
|
||||
|
||||
ret = dce_admin_init(d);
|
||||
if (ret) {
|
||||
dce_err(d, "dce admin interface init failed");
|
||||
goto err_admin_interface_init;
|
||||
}
|
||||
|
||||
ret = dce_client_init(d);
|
||||
if (ret) {
|
||||
dce_err(d, "dce client workqueue init failed");
|
||||
goto err_client_init;
|
||||
}
|
||||
|
||||
ret = dce_work_cond_sw_resource_init(d);
|
||||
if (ret) {
|
||||
dce_err(d, "dce sw resource init failed");
|
||||
goto err_sw_init;
|
||||
}
|
||||
|
||||
ret = dce_fsm_init(d);
|
||||
if (ret) {
|
||||
dce_err(d, "dce FSM init failed");
|
||||
goto err_fsm_init;
|
||||
}
|
||||
|
||||
dce_fsm_start(d);
|
||||
|
||||
return ret;
|
||||
|
||||
err_fsm_init:
|
||||
dce_work_cond_sw_resource_deinit(d);
|
||||
err_sw_init:
|
||||
dce_client_deinit(d);
|
||||
err_client_init:
|
||||
dce_admin_deinit(d);
|
||||
err_admin_interface_init:
|
||||
dce_boot_interface_deinit(d);
|
||||
err_boot_interface_init:
|
||||
d->boot_status |= DCE_STATUS_FAILED;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_driver_deinit - Release various sw resources
|
||||
* associated with dce.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
|
||||
void dce_driver_deinit(struct tegra_dce *d)
|
||||
{
|
||||
/* TODO : Reset DCE ? */
|
||||
dce_fsm_stop(d);
|
||||
|
||||
dce_fsm_deinit(d);
|
||||
|
||||
dce_work_cond_sw_resource_deinit(d);
|
||||
|
||||
dce_client_deinit(d);
|
||||
|
||||
dce_admin_deinit(d);
|
||||
|
||||
dce_boot_interface_deinit(d);
|
||||
|
||||
dce_release_fw(d, d->fw_data);
|
||||
}
|
||||
158
drivers/platform/tegra/dce/dce-ipc-signal.c
Normal file
158
drivers/platform/tegra/dce/dce-ipc-signal.c
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2023, NVIDIA CORPORATION. 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>
|
||||
#include <dce-ipc.h>
|
||||
#include <dce-util-common.h>
|
||||
#include <interface/dce-interface.h>
|
||||
|
||||
static struct dce_ipc_signal_instance *mb_signals[DCE_NUM_MBOX_REGS];
|
||||
|
||||
static void dce_ipc_mbox_notify(struct tegra_dce *d,
|
||||
struct dce_ipc_signal_instance *s)
|
||||
{
|
||||
if (s == NULL) {
|
||||
dce_info(d, "Invalid signal instance for notification");
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->sema_num < DCE_NUM_SEMA_REGS)
|
||||
dce_ss_set(d, s->sema_bit, s->sema_num);
|
||||
|
||||
dce_mailbox_set_full_interrupt(d, s->form.mbox.mb_type);
|
||||
}
|
||||
|
||||
static void dce_ipc_mbox_handle_signal(struct tegra_dce *d, void *data)
|
||||
{
|
||||
u32 sema_val;
|
||||
struct dce_ipc_channel *ch;
|
||||
struct dce_ipc_signal_instance *s;
|
||||
struct dce_ipc_signal_instance *cur_s;
|
||||
|
||||
s = (struct dce_ipc_signal_instance *)data;
|
||||
if ((s == NULL) || (s->signal == NULL) ||
|
||||
(s->signal->ch == NULL) ||
|
||||
(s->form.mbox.mb_num > DCE_NUM_MBOX_REGS)) {
|
||||
dce_err(d, "Invalid signal instance in mailbox callback");
|
||||
return;
|
||||
}
|
||||
|
||||
for (cur_s = s; cur_s != NULL; cur_s = cur_s->next) {
|
||||
if (cur_s->sema_num < DCE_NUM_SEMA_REGS) {
|
||||
sema_val = dce_ss_get_state(d, cur_s->sema_num);
|
||||
if ((sema_val & BIT(cur_s->sema_bit)) == 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
dce_ss_clear(d, cur_s->sema_num, BIT(cur_s->sema_bit));
|
||||
|
||||
ch = cur_s->signal->ch;
|
||||
|
||||
dce_admin_ipc_handle_signal(d, ch->ch_type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock is acquired in dce-ipc before calling this API.
|
||||
* Shouldn't be called from anywhere else.
|
||||
*/
|
||||
int dce_ipc_init_signaling(struct tegra_dce *d, struct dce_ipc_channel *ch)
|
||||
{
|
||||
u8 mb_type;
|
||||
u32 to_mbox;
|
||||
u32 from_mbox;
|
||||
int ret = 0;
|
||||
struct dce_ipc_signal_instance *temp_s;
|
||||
struct dce_ipc_signal_instance *to_d = &ch->signal.to_d;
|
||||
struct dce_ipc_signal_instance *from_d = &ch->signal.from_d;
|
||||
|
||||
ch->signal.ch = ch;
|
||||
|
||||
if ((from_d == NULL) || (to_d == NULL)) {
|
||||
dce_err(d, "Invalid signal instances");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mb_type = to_d->form.mbox.mb_type;
|
||||
if (to_d->form.mbox.mb_type !=
|
||||
from_d->form.mbox.mb_type) {
|
||||
dce_err(d, "Mailbox type doesn't match");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
to_mbox = to_d->form.mbox.mb_num;
|
||||
from_mbox = from_d->form.mbox.mb_num;
|
||||
|
||||
to_d->signal = &ch->signal;
|
||||
|
||||
if (to_d->type == DCE_IPC_SIGNAL_MAILBOX) {
|
||||
to_d->signal->notify = dce_ipc_mbox_notify;
|
||||
mb_signals[to_mbox] = to_d;
|
||||
} else {
|
||||
dce_info(d, "Signal type not supported : [%d]", to_d->type);
|
||||
}
|
||||
|
||||
from_d->signal = &ch->signal;
|
||||
|
||||
if (from_d->type == DCE_IPC_SIGNAL_MAILBOX) {
|
||||
if ((from_d->next != NULL)
|
||||
|| (from_mbox >= DCE_NUM_MBOX_REGS)) {
|
||||
dce_err(d, "Invalid Signal Instance");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
temp_s = mb_signals[from_mbox];
|
||||
if (temp_s != NULL)
|
||||
from_d->next = temp_s;
|
||||
|
||||
mb_signals[from_d->form.mbox.mb_num] = from_d;
|
||||
} else {
|
||||
dce_info(d, "Signal type not supported : [%d]", from_d->type);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO : Call this API on a conditional basis.
|
||||
*/
|
||||
ret = dce_mailbox_init_interface(d, mb_type,
|
||||
to_mbox, from_mbox, NULL, (void *)from_d,
|
||||
dce_ipc_mbox_handle_signal);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock is acquired in dce-ipc before calling this API.
|
||||
* Shouldn't be called from anywhere else.
|
||||
*/
|
||||
void dce_ipc_deinit_signaling(struct tegra_dce *d, struct dce_ipc_channel *ch)
|
||||
{
|
||||
u8 mb_type;
|
||||
struct dce_ipc_signal_instance *to_d = &ch->signal.to_d;
|
||||
struct dce_ipc_signal_instance *from_d = &ch->signal.from_d;
|
||||
|
||||
/**
|
||||
* TODO : Nullify other signal parameters as well.
|
||||
*/
|
||||
mb_type = to_d->form.mbox.mb_type;
|
||||
if (to_d->form.mbox.mb_type !=
|
||||
from_d->form.mbox.mb_type) {
|
||||
dce_err(d, "Mailbox type doesn't match");
|
||||
return;
|
||||
}
|
||||
dce_mailbox_deinit_interface(d, mb_type);
|
||||
|
||||
ch->signal.ch = NULL;
|
||||
}
|
||||
891
drivers/platform/tegra/dce/dce-ipc.c
Normal file
891
drivers/platform/tegra/dce/dce-ipc.c
Normal file
@@ -0,0 +1,891 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2023, NVIDIA CORPORATION. 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 <linux/version.h>
|
||||
|
||||
#include <dce.h>
|
||||
#include <dce-ipc.h>
|
||||
#include <dce-util-common.h>
|
||||
#include <interface/dce-interface.h>
|
||||
#include <interface/dce-ipc-header.h>
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/dce_events.h>
|
||||
|
||||
static struct dce_ipc_channel ivc_channels[DCE_IPC_CH_KMD_TYPE_MAX] = {
|
||||
[DCE_IPC_CH_KMD_TYPE_ADMIN] = {
|
||||
.flags = DCE_IPC_CHANNEL_VALID
|
||||
| DCE_IPC_CHANNEL_MSG_HEADER,
|
||||
.ch_type = DCE_IPC_CH_KMD_TYPE_ADMIN,
|
||||
.ipc_type = DCE_IPC_TYPE_ADMIN,
|
||||
.signal = {
|
||||
.to_d = {
|
||||
.type = DCE_IPC_SIGNAL_MAILBOX,
|
||||
.sema_num = DCE_NUM_SEMA_REGS,
|
||||
.sema_bit = 0U,
|
||||
.form = {
|
||||
.mbox = {
|
||||
.mb_type = DCE_MAILBOX_ADMIN_INTERFACE,
|
||||
.mb_num = DCE_MBOX_TO_DCE_ADMIN,
|
||||
},
|
||||
},
|
||||
.signal = NULL,
|
||||
.next = NULL,
|
||||
},
|
||||
.from_d = {
|
||||
.type = DCE_IPC_SIGNAL_MAILBOX,
|
||||
.sema_num = DCE_NUM_SEMA_REGS,
|
||||
.sema_bit = 0U,
|
||||
.form = {
|
||||
.mbox = {
|
||||
.mb_type = DCE_MAILBOX_ADMIN_INTERFACE,
|
||||
.mb_num = DCE_MBOX_FROM_DCE_ADMIN,
|
||||
},
|
||||
},
|
||||
.signal = NULL,
|
||||
.next = NULL,
|
||||
},
|
||||
},
|
||||
.q_info = {
|
||||
.nframes = DCE_ADMIN_CMD_MAX_NFRAMES,
|
||||
.frame_sz = DCE_ADMIN_CMD_MAX_FSIZE,
|
||||
},
|
||||
},
|
||||
[DCE_IPC_CH_KMD_TYPE_RM] = {
|
||||
.flags = DCE_IPC_CHANNEL_VALID
|
||||
| DCE_IPC_CHANNEL_MSG_HEADER,
|
||||
.ch_type = DCE_IPC_CH_KMD_TYPE_RM,
|
||||
.ipc_type = DCE_IPC_TYPE_DISPRM,
|
||||
.signal = {
|
||||
.to_d = {
|
||||
.type = DCE_IPC_SIGNAL_MAILBOX,
|
||||
.sema_num = DCE_NUM_SEMA_REGS,
|
||||
.sema_bit = 0U,
|
||||
.form = {
|
||||
.mbox = {
|
||||
.mb_type = DCE_MAILBOX_DISPRM_INTERFACE,
|
||||
.mb_num = DCE_MBOX_TO_DCE_RM,
|
||||
},
|
||||
},
|
||||
.signal = NULL,
|
||||
.next = NULL,
|
||||
},
|
||||
.from_d = {
|
||||
.type = DCE_IPC_SIGNAL_MAILBOX,
|
||||
.sema_num = DCE_NUM_SEMA_REGS,
|
||||
.sema_bit = 0U,
|
||||
.form = {
|
||||
.mbox = {
|
||||
.mb_type = DCE_MAILBOX_DISPRM_INTERFACE,
|
||||
.mb_num = DCE_MBOX_FROM_DCE_RM,
|
||||
},
|
||||
},
|
||||
.signal = NULL,
|
||||
.next = NULL,
|
||||
},
|
||||
},
|
||||
.q_info = {
|
||||
.nframes = DCE_DISPRM_CMD_MAX_NFRAMES,
|
||||
.frame_sz = DCE_DISPRM_CMD_MAX_FSIZE,
|
||||
},
|
||||
},
|
||||
[DCE_IPC_CH_KMD_TYPE_RM_NOTIFY] = {
|
||||
.flags = DCE_IPC_CHANNEL_VALID
|
||||
| DCE_IPC_CHANNEL_MSG_HEADER,
|
||||
.ch_type = DCE_IPC_CH_KMD_TYPE_RM_NOTIFY,
|
||||
.ipc_type = DCE_IPC_TYPE_RM_NOTIFY,
|
||||
.signal = {
|
||||
.to_d = {
|
||||
.type = DCE_IPC_SIGNAL_MAILBOX,
|
||||
.sema_num = DCE_NUM_SEMA_REGS,
|
||||
.sema_bit = 0U,
|
||||
.form = {
|
||||
.mbox = {
|
||||
.mb_type = DCE_MAILBOX_DISPRM_NOTIFY_INTERFACE,
|
||||
.mb_num = DCE_MBOX_FROM_DCE_RM_EVENT_NOTIFY,
|
||||
},
|
||||
},
|
||||
.signal = NULL,
|
||||
.next = NULL,
|
||||
},
|
||||
.from_d = {
|
||||
.type = DCE_IPC_SIGNAL_MAILBOX,
|
||||
.sema_num = DCE_NUM_SEMA_REGS,
|
||||
.sema_bit = 0U,
|
||||
.form = {
|
||||
.mbox = {
|
||||
.mb_type = DCE_MAILBOX_DISPRM_NOTIFY_INTERFACE,
|
||||
.mb_num = DCE_MBOX_TO_DCE_RM_EVENT_NOTIFY,
|
||||
},
|
||||
},
|
||||
.signal = NULL,
|
||||
.next = NULL,
|
||||
},
|
||||
},
|
||||
.q_info = {
|
||||
.nframes = DCE_DISPRM_EVENT_NOTIFY_CMD_MAX_NFRAMES,
|
||||
.frame_sz = DCE_DISPRM_EVENT_NOTIFY_CMD_MAX_FSIZE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_ipc_allocate_region - Allocates IPC region for IVC
|
||||
*
|
||||
* @ch : Pointer to the pertinent dce_ipc_channel.
|
||||
* @q_size : IVC queue size.
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
int dce_ipc_allocate_region(struct tegra_dce *d)
|
||||
{
|
||||
unsigned long tot_q_sz;
|
||||
unsigned long tot_ivc_q_sz;
|
||||
struct device *dev;
|
||||
struct dce_ipc_region *region;
|
||||
|
||||
dev = dev_from_dce(d);
|
||||
region = &d->d_ipc.region;
|
||||
|
||||
tot_q_sz = ((DCE_ADMIN_CMD_MAX_NFRAMES *
|
||||
tegra_ivc_align(DCE_ADMIN_CMD_MAX_FSIZE) * 2) +
|
||||
(DCE_DISPRM_CMD_MAX_NFRAMES *
|
||||
tegra_ivc_align(DCE_DISPRM_CMD_MAX_FSIZE) * 2) +
|
||||
(DCE_ADMIN_CMD_MAX_NFRAMES *
|
||||
tegra_ivc_align(DCE_ADMIN_CMD_CHAN_FSIZE) * 2) +
|
||||
(DCE_DISPRM_EVENT_NOTIFY_CMD_MAX_NFRAMES *
|
||||
tegra_ivc_align(DCE_DISPRM_EVENT_NOTIFY_CMD_MAX_FSIZE) * 2)
|
||||
);
|
||||
|
||||
tot_ivc_q_sz = tegra_ivc_total_queue_size(tot_q_sz);
|
||||
region->size = dce_get_nxt_pow_of_2(&tot_ivc_q_sz, 32);
|
||||
region->base = dma_alloc_coherent(dev, region->size,
|
||||
®ion->iova, GFP_KERNEL | __GFP_ZERO);
|
||||
if (!region->base)
|
||||
return -ENOMEM;
|
||||
|
||||
region->s_offset = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_ipc_free_region - Frees up the IPC region for IVC
|
||||
*
|
||||
* @d : Pointer to the tegra_dce struct.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
void dce_ipc_free_region(struct tegra_dce *d)
|
||||
{
|
||||
struct device *dev;
|
||||
struct dce_ipc_region *region;
|
||||
|
||||
dev = dev_from_dce(d);
|
||||
region = &d->d_ipc.region;
|
||||
|
||||
dma_free_coherent(dev, region->size,
|
||||
(void *)region->base, region->iova);
|
||||
|
||||
region->s_offset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_ipc_signal_target - Generic function to signal target.
|
||||
*
|
||||
* @d_ivc : Pointer to struct tegra_ivc.
|
||||
*
|
||||
* Do not take a channel lock here.
|
||||
*
|
||||
* Return : Void.
|
||||
*/
|
||||
static void dce_ipc_signal_target(struct tegra_ivc *ivc, void *data)
|
||||
{
|
||||
}
|
||||
|
||||
static int _dce_ipc_wait(struct tegra_dce *d, u32 w_type, u32 ch_type)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_ipc_channel *ch;
|
||||
|
||||
if (ch_type >= DCE_IPC_CH_KMD_TYPE_MAX) {
|
||||
dce_err(d, "Invalid Channel Type : [%d]", ch_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ch = d->d_ipc.ch[ch_type];
|
||||
if (ch == NULL) {
|
||||
dce_err(d, "Invalid Channel Data for type : [%d]", ch_type);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ch->w_type = w_type;
|
||||
|
||||
dce_mutex_unlock(&ch->lock);
|
||||
|
||||
if (ch_type == DCE_IPC_TYPE_ADMIN)
|
||||
ret = dce_admin_ipc_wait(d, w_type);
|
||||
else
|
||||
ret = dce_client_ipc_wait(d, ch_type);
|
||||
|
||||
dce_mutex_lock(&ch->lock);
|
||||
|
||||
ch->w_type = DCE_IPC_WAIT_TYPE_INVALID;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 dce_ipc_get_cur_wait_type(struct tegra_dce *d, u32 ch_type)
|
||||
{
|
||||
uint32_t w_type;
|
||||
struct dce_ipc_channel *ch;
|
||||
|
||||
if (ch_type >= DCE_IPC_CH_KMD_TYPE_MAX) {
|
||||
dce_err(d, "Invalid Channel Type : [%d]", ch_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ch = d->d_ipc.ch[ch_type];
|
||||
if (ch == NULL) {
|
||||
dce_err(d, "Invalid Channel Data for type : [%d]", ch_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dce_mutex_lock(&ch->lock);
|
||||
|
||||
w_type = ch->w_type;
|
||||
|
||||
dce_mutex_unlock(&ch->lock);
|
||||
|
||||
return w_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_ipc_channel_init - Initializes the underlying IPC channel to
|
||||
* be used for all bi-directional messaging.
|
||||
* @d : Pointer to struct tegra_dce.
|
||||
* @type : Type of interface for which this channel is needed.
|
||||
*
|
||||
* Return : 0 if successful.
|
||||
*/
|
||||
int dce_ipc_channel_init(struct tegra_dce *d, u32 ch_type)
|
||||
{
|
||||
u32 q_sz;
|
||||
u32 msg_sz;
|
||||
int ret = 0;
|
||||
struct device *dev;
|
||||
struct dce_ipc_region *r;
|
||||
struct dce_ipc_channel *ch;
|
||||
struct dce_ipc_queue_info *q_info;
|
||||
#if (KERNEL_VERSION(6, 2, 0) <= LINUX_VERSION_CODE)
|
||||
struct iosys_map rx, tx;
|
||||
#endif
|
||||
|
||||
if (ch_type >= DCE_IPC_CH_KMD_TYPE_MAX) {
|
||||
dce_err(d, "Invalid ivc channel ch_type : [%d]", ch_type);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ch = &ivc_channels[ch_type];
|
||||
if (!ch) {
|
||||
dce_err(d, "Invalid ivc channel for this ch_type : [%d]",
|
||||
ch_type);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = dce_mutex_init(&ch->lock);
|
||||
if (ret) {
|
||||
dce_err(d, "dce lock initialization failed for mailbox");
|
||||
goto out;
|
||||
}
|
||||
|
||||
dce_mutex_lock(&ch->lock);
|
||||
|
||||
if ((ch->flags & DCE_IPC_CHANNEL_VALID) == 0U) {
|
||||
dce_info(d, "Invalid Channel State [0x%x] for ch_type [%d]",
|
||||
ch->flags, ch_type);
|
||||
goto out_lock_destroy;
|
||||
}
|
||||
|
||||
ch->d = d;
|
||||
|
||||
ret = dce_ipc_init_signaling(d, ch);
|
||||
if (ret) {
|
||||
dce_err(d, "Signaling init failed");
|
||||
goto out_lock_destroy;
|
||||
}
|
||||
|
||||
q_info = &ch->q_info;
|
||||
msg_sz = tegra_ivc_align(q_info->frame_sz);
|
||||
q_sz = tegra_ivc_total_queue_size(msg_sz * q_info->nframes);
|
||||
|
||||
r = &d->d_ipc.region;
|
||||
if (!r->base) {
|
||||
ret = -ENOMEM;
|
||||
goto out_lock_destroy;
|
||||
}
|
||||
|
||||
dev = dev_from_dce(d);
|
||||
|
||||
#if (KERNEL_VERSION(6, 2, 0) <= LINUX_VERSION_CODE)
|
||||
iosys_map_set_vaddr(&rx, r->base + r->s_offset);
|
||||
iosys_map_set_vaddr(&tx, r->base + r->s_offset + q_sz);
|
||||
|
||||
ret = tegra_ivc_init(&ch->d_ivc, NULL, &rx, r->iova + r->s_offset, &tx,
|
||||
r->iova + r->s_offset + q_sz, q_info->nframes, msg_sz,
|
||||
dce_ipc_signal_target, NULL);
|
||||
#else
|
||||
ret = tegra_ivc_init(&ch->d_ivc, NULL, r->base + r->s_offset,
|
||||
r->iova + r->s_offset, r->base + r->s_offset + q_sz,
|
||||
r->iova + r->s_offset + q_sz, q_info->nframes, msg_sz,
|
||||
dce_ipc_signal_target, NULL);
|
||||
#endif
|
||||
if (ret) {
|
||||
dce_err(d, "IVC creation failed");
|
||||
goto out_lock_destroy;
|
||||
}
|
||||
|
||||
ch->flags |= DCE_IPC_CHANNEL_INITIALIZED;
|
||||
|
||||
q_info->rx_iova = r->iova + r->s_offset;
|
||||
q_info->tx_iova = r->iova + r->s_offset + q_sz;
|
||||
|
||||
trace_ivc_channel_init_complete(d, ch);
|
||||
|
||||
d->d_ipc.ch[ch_type] = ch;
|
||||
r->s_offset += (2 * q_sz);
|
||||
|
||||
out_lock_destroy:
|
||||
dce_mutex_unlock(&ch->lock);
|
||||
if (ret)
|
||||
dce_mutex_destroy(&ch->lock);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_ivc_channel_deinit - Releases resources for a ivc channel
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @id : Channel Id.
|
||||
*/
|
||||
void dce_ipc_channel_deinit(struct tegra_dce *d, u32 ch_type)
|
||||
{
|
||||
struct dce_ipc_channel *ch = d->d_ipc.ch[ch_type];
|
||||
|
||||
if (ch == NULL || (ch->flags & DCE_IPC_CHANNEL_INITIALIZED) == 0U) {
|
||||
dce_info(d, "Invalid IVC Channel [%d]", ch_type);
|
||||
return;
|
||||
}
|
||||
|
||||
dce_mutex_lock(&ch->lock);
|
||||
|
||||
dce_ipc_deinit_signaling(d, ch);
|
||||
|
||||
ch->flags &= ~DCE_IPC_CHANNEL_INITIALIZED;
|
||||
ch->flags &= ~DCE_IPC_CHANNEL_SYNCED;
|
||||
|
||||
d->d_ipc.ch[ch_type] = NULL;
|
||||
|
||||
dce_mutex_unlock(&ch->lock);
|
||||
|
||||
dce_mutex_destroy(&ch->lock);
|
||||
|
||||
}
|
||||
|
||||
struct tegra_dce *dce_ipc_get_dce_from_ch(u32 ch_type)
|
||||
{
|
||||
struct tegra_dce *d = NULL;
|
||||
struct dce_ipc_channel *ch = NULL;
|
||||
|
||||
if (ch_type >= DCE_IPC_CH_KMD_TYPE_MAX)
|
||||
goto out;
|
||||
|
||||
ch = &ivc_channels[ch_type];
|
||||
|
||||
dce_mutex_lock(&ch->lock);
|
||||
|
||||
d = ch->d;
|
||||
|
||||
dce_mutex_unlock(&ch->lock);
|
||||
|
||||
out:
|
||||
return d;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_ipc_channel_ready - Checks if channel is ready to use
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @id : Channel Id.
|
||||
*
|
||||
* Return : true if channel ready to use.
|
||||
*/
|
||||
bool dce_ipc_channel_is_ready(struct tegra_dce *d, u32 ch_type)
|
||||
{
|
||||
bool is_est;
|
||||
|
||||
struct dce_ipc_channel *ch = d->d_ipc.ch[ch_type];
|
||||
|
||||
dce_mutex_lock(&ch->lock);
|
||||
|
||||
is_est = (tegra_ivc_notified(&ch->d_ivc) ? false : true);
|
||||
|
||||
ch->signal.notify(d, &ch->signal.to_d);
|
||||
|
||||
dce_mutex_unlock(&ch->lock);
|
||||
|
||||
return is_est;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_ipc_channel_synced - Checks if channel is in synced state
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @id : Channel Id.
|
||||
*
|
||||
* Return : true if channel is in synced state.
|
||||
*/
|
||||
bool dce_ipc_channel_is_synced(struct tegra_dce *d, u32 ch_type)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
struct dce_ipc_channel *ch = d->d_ipc.ch[ch_type];
|
||||
|
||||
dce_mutex_lock(&ch->lock);
|
||||
|
||||
ret = (ch->flags & DCE_IPC_CHANNEL_SYNCED) ? true : false;
|
||||
|
||||
dce_mutex_unlock(&ch->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_ipc_channel_reset - Resets the channel and completes
|
||||
* the handshake with the remote.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @id : Channel Id.
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
void dce_ipc_channel_reset(struct tegra_dce *d, u32 ch_type)
|
||||
{
|
||||
struct dce_ipc_channel *ch = d->d_ipc.ch[ch_type];
|
||||
|
||||
dce_mutex_lock(&ch->lock);
|
||||
|
||||
tegra_ivc_reset(&ch->d_ivc);
|
||||
|
||||
trace_ivc_channel_reset_triggered(d, ch);
|
||||
|
||||
ch->flags &= ~DCE_IPC_CHANNEL_SYNCED;
|
||||
|
||||
ch->signal.notify(d, &ch->signal.to_d);
|
||||
|
||||
dce_mutex_unlock(&ch->lock);
|
||||
|
||||
do {
|
||||
if (dce_ipc_channel_is_ready(d, ch_type) == true)
|
||||
break;
|
||||
|
||||
} while (true);
|
||||
|
||||
dce_mutex_lock(&ch->lock);
|
||||
|
||||
ch->flags |= DCE_IPC_CHANNEL_SYNCED;
|
||||
|
||||
trace_ivc_channel_reset_complete(d, ch);
|
||||
|
||||
dce_mutex_unlock(&ch->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_ipc_get_next_write_buff - waits for the next write frame.
|
||||
*
|
||||
* @ch : Pointer to the pertinent channel.
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
static int _dce_ipc_get_next_write_buff(struct dce_ipc_channel *ch)
|
||||
{
|
||||
#if (KERNEL_VERSION(6, 2, 0) <= LINUX_VERSION_CODE)
|
||||
int err;
|
||||
|
||||
err = tegra_ivc_write_get_next_frame(&ch->d_ivc, &ch->obuff);
|
||||
if (err) {
|
||||
iosys_map_clear(&ch->obuff);
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
void *frame = NULL;
|
||||
|
||||
frame = tegra_ivc_write_get_next_frame(&ch->d_ivc);
|
||||
|
||||
if (IS_ERR(frame)) {
|
||||
ch->obuff = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ch->obuff = frame;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_ipc_write_channel - Writes to an ivc channel.
|
||||
*
|
||||
* @ch : Pointer to the pertinent channel.
|
||||
* @data : Pointer to the data to be written.
|
||||
* @size : Size of the data to be written.
|
||||
*
|
||||
* Return : 0 if successful.
|
||||
*/
|
||||
static int _dce_ipc_write_channel(struct dce_ipc_channel *ch,
|
||||
const void *data, size_t size)
|
||||
{
|
||||
struct dce_ipc_header *hdr;
|
||||
|
||||
/**
|
||||
* Add actual length information to the top
|
||||
* of the IVC frame
|
||||
*/
|
||||
|
||||
#if (KERNEL_VERSION(6, 2, 0) <= LINUX_VERSION_CODE)
|
||||
if ((ch->flags & DCE_IPC_CHANNEL_MSG_HEADER) != 0U) {
|
||||
iosys_map_wr_field(&ch->obuff, 0, struct dce_ipc_header, length,
|
||||
size);
|
||||
iosys_map_incr(&ch->obuff, sizeof(*hdr));
|
||||
}
|
||||
|
||||
if (data && size > 0)
|
||||
iosys_map_memcpy_to(&ch->obuff, 0, data, size);
|
||||
#else
|
||||
if ((ch->flags & DCE_IPC_CHANNEL_MSG_HEADER) != 0U) {
|
||||
hdr = (struct dce_ipc_header *)ch->obuff;
|
||||
hdr->length = (uint32_t)size;
|
||||
ch->obuff = (void *)(hdr + 1U);
|
||||
}
|
||||
|
||||
if (data && size > 0)
|
||||
memcpy(ch->obuff, data, size);
|
||||
#endif
|
||||
|
||||
return tegra_ivc_write_advance(&ch->d_ivc);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_ipc_send_message - Sends messages over ipc.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @id : Channel Id.
|
||||
* @data : Pointer to the data to be written.
|
||||
* @size : Size of the data to be written.
|
||||
*
|
||||
* Return : 0 if successful.
|
||||
*/
|
||||
int dce_ipc_send_message(struct tegra_dce *d, u32 ch_type,
|
||||
const void *data, size_t size)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_ipc_channel *ch
|
||||
= d->d_ipc.ch[ch_type];
|
||||
|
||||
dce_mutex_lock(&ch->lock);
|
||||
|
||||
trace_ivc_send_req_received(d, ch);
|
||||
|
||||
ret = _dce_ipc_get_next_write_buff(ch);
|
||||
if (ret) {
|
||||
dce_err(ch->d, "Error getting next free buf to write");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = _dce_ipc_write_channel(ch, data, size);
|
||||
if (ret) {
|
||||
dce_err(ch->d, "Error writing to channel");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ch->signal.notify(d, &ch->signal.to_d);
|
||||
|
||||
trace_ivc_send_complete(d, ch);
|
||||
|
||||
out:
|
||||
dce_mutex_unlock(&ch->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_ipc_get_next_read_buff - waits for the next write frame.
|
||||
*
|
||||
* @ch : Pointer to the pertinent channel.
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
static int _dce_ipc_get_next_read_buff(struct dce_ipc_channel *ch)
|
||||
{
|
||||
#if (KERNEL_VERSION(6, 2, 0) <= LINUX_VERSION_CODE)
|
||||
int err;
|
||||
|
||||
err = tegra_ivc_read_get_next_frame(&ch->d_ivc, &ch->ibuff);
|
||||
if (err) {
|
||||
iosys_map_clear(&ch->ibuff);
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
void *frame = NULL;
|
||||
|
||||
frame = tegra_ivc_read_get_next_frame(&ch->d_ivc);
|
||||
|
||||
if (IS_ERR(frame)) {
|
||||
ch->ibuff = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ch->ibuff = frame;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_ipc_read_channel - Writes to an ivc channel.
|
||||
*
|
||||
* @ch : Pointer to the pertinent channel.
|
||||
* @data : Pointer to the data to be read.
|
||||
* @size : Size of the data to be read.
|
||||
*
|
||||
* Return : 0 if successful.
|
||||
*/
|
||||
static int _dce_ipc_read_channel(struct dce_ipc_channel *ch,
|
||||
void *data, size_t size)
|
||||
{
|
||||
struct dce_ipc_header *hdr;
|
||||
|
||||
/**
|
||||
* Get actual length information from the top
|
||||
* of the IVC frame
|
||||
*/
|
||||
#if (KERNEL_VERSION(6, 2, 0) <= LINUX_VERSION_CODE)
|
||||
if ((ch->flags & DCE_IPC_CHANNEL_MSG_HEADER) != 0U) {
|
||||
iosys_map_wr_field(&ch->ibuff, 0, struct dce_ipc_header, length,
|
||||
size);
|
||||
iosys_map_incr(&ch->ibuff, sizeof(*hdr));
|
||||
}
|
||||
|
||||
if (data && size > 0)
|
||||
iosys_map_memcpy_from(data, &ch->ibuff, 0, size);
|
||||
#else
|
||||
if ((ch->flags & DCE_IPC_CHANNEL_MSG_HEADER) != 0U) {
|
||||
hdr = (struct dce_ipc_header *)ch->ibuff;
|
||||
size = (size_t)(hdr->length);
|
||||
ch->ibuff = (void *)(hdr + 1U);
|
||||
}
|
||||
|
||||
if (data && size > 0)
|
||||
memcpy(data, ch->ibuff, size);
|
||||
#endif
|
||||
|
||||
return tegra_ivc_read_advance(&ch->d_ivc);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_ipc_read_message - Reads messages over ipc.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @id : Channel Id.
|
||||
* @data : Pointer to the data to be read.
|
||||
* @size : Size of the data to be read.
|
||||
*
|
||||
* Return : 0 if successful.
|
||||
*/
|
||||
int dce_ipc_read_message(struct tegra_dce *d, u32 ch_type,
|
||||
void *data, size_t size)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_ipc_channel *ch = d->d_ipc.ch[ch_type];
|
||||
|
||||
dce_mutex_lock(&ch->lock);
|
||||
|
||||
trace_ivc_receive_req_received(d, ch);
|
||||
|
||||
ret = _dce_ipc_get_next_read_buff(ch);
|
||||
if (ret) {
|
||||
dce_debug(ch->d, "No Msg to read");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = _dce_ipc_read_channel(ch, data, size);
|
||||
if (ret) {
|
||||
dce_err(ch->d, "Error reading from channel");
|
||||
goto out;
|
||||
}
|
||||
|
||||
trace_ivc_receive_req_complete(d, ch);
|
||||
|
||||
out:
|
||||
dce_mutex_unlock(&ch->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_ipc_send_message_sync - Sends messages on a channel
|
||||
* synchronously and waits for an ack.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @id : Channel Id.
|
||||
* @msg : Pointer to the message to be sent/received.
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
int dce_ipc_send_message_sync(struct tegra_dce *d, u32 ch_type,
|
||||
struct dce_ipc_message *msg)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_ipc_channel *ch = d->d_ipc.ch[ch_type];
|
||||
|
||||
ret = dce_ipc_send_message(d, ch_type, msg->tx.data, msg->tx.size);
|
||||
if (ret) {
|
||||
dce_err(ch->d, "Error in sending message to DCE");
|
||||
goto done;
|
||||
}
|
||||
|
||||
dce_mutex_lock(&ch->lock);
|
||||
ret = _dce_ipc_wait(ch->d, DCE_IPC_WAIT_TYPE_RPC, ch_type);
|
||||
dce_mutex_unlock(&ch->lock);
|
||||
if (ret) {
|
||||
dce_err(ch->d, "Error in waiting for ack");
|
||||
goto done;
|
||||
}
|
||||
|
||||
trace_ivc_wait_complete(d, ch);
|
||||
|
||||
ret = dce_ipc_read_message(d, ch_type, msg->rx.data, msg->rx.size);
|
||||
if (ret) {
|
||||
dce_err(ch->d, "Error in reading DCE msg for ch_type [%d]",
|
||||
ch_type);
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_ipc_get_channel_info - Provides information about frames details
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @ch_index : Channel Index.
|
||||
* @q_info : Pointer to struct dce_ipc_queue_info
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
int dce_ipc_get_channel_info(struct tegra_dce *d,
|
||||
struct dce_ipc_queue_info *q_info, u32 ch_index)
|
||||
{
|
||||
struct dce_ipc_channel *ch = d->d_ipc.ch[ch_index];
|
||||
|
||||
if (ch == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
dce_mutex_lock(&ch->lock);
|
||||
|
||||
memcpy(q_info, &ch->q_info, sizeof(ch->q_info));
|
||||
|
||||
dce_mutex_unlock(&ch->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_ipc_get_region_iova_info - Provides iova details for ipc region
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @iova : Iova start address.
|
||||
* @size : Iova size
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
int dce_ipc_get_region_iova_info(struct tegra_dce *d, u64 *iova, u32 *size)
|
||||
{
|
||||
struct dce_ipc_region *r = &d->d_ipc.region;
|
||||
|
||||
if (!r->base)
|
||||
return -ENOMEM;
|
||||
|
||||
*iova = r->iova;
|
||||
*size = r->size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* dce_ipc_handle_notification - Handles the notification from remote
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
* @id : Channel Index
|
||||
*
|
||||
* Return : True if the worker thread needs to wake up
|
||||
*/
|
||||
bool dce_ipc_is_data_available(struct tegra_dce *d, u32 ch_type)
|
||||
{
|
||||
bool ret = false;
|
||||
#if (KERNEL_VERSION(6, 2, 0) <= LINUX_VERSION_CODE)
|
||||
struct iosys_map map;
|
||||
#else
|
||||
void *frame;
|
||||
#endif
|
||||
struct dce_ipc_channel *ch = d->d_ipc.ch[ch_type];
|
||||
|
||||
dce_mutex_lock(&ch->lock);
|
||||
|
||||
#if (KERNEL_VERSION(6, 2, 0) <= LINUX_VERSION_CODE)
|
||||
if (!tegra_ivc_read_get_next_frame(&ch->d_ivc, &map))
|
||||
ret = true;
|
||||
#else
|
||||
frame = tegra_ivc_read_get_next_frame(&ch->d_ivc);
|
||||
if (!IS_ERR(frame))
|
||||
ret = true;
|
||||
#endif
|
||||
|
||||
dce_mutex_unlock(&ch->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* dce_ipc_get_ipc_type - Returns the ipc_type for the channel.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
* @id : Channel Index
|
||||
*
|
||||
* Return : True if the worker thread needs to wake up
|
||||
*/
|
||||
uint32_t dce_ipc_get_ipc_type(struct tegra_dce *d, u32 ch_type)
|
||||
{
|
||||
uint32_t ipc_type;
|
||||
struct dce_ipc_channel *ch = d->d_ipc.ch[ch_type];
|
||||
|
||||
dce_mutex_lock(&ch->lock);
|
||||
|
||||
ipc_type = ch->ipc_type;
|
||||
|
||||
dce_mutex_unlock(&ch->lock);
|
||||
|
||||
return ipc_type;
|
||||
}
|
||||
297
drivers/platform/tegra/dce/dce-mailbox.c
Normal file
297
drivers/platform/tegra/dce/dce-mailbox.c
Normal file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2022, NVIDIA CORPORATION. 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>
|
||||
#include <dce-mailbox.h>
|
||||
#include <dce-util-common.h>
|
||||
#include <interface/dce-interface.h>
|
||||
#include <interface/dce-boot-cmds.h>
|
||||
|
||||
|
||||
#define CCPLEX_HSP_IE 1U /* TODO : Have an api to read from platform data */
|
||||
#define DCE_MAILBOX_FULL_INT_SHIFT 8U
|
||||
|
||||
/**
|
||||
* dce_hsp_get_irq_sources - gets the interrupt sources.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : bitmap for mailbox ids that triggered the irqs.
|
||||
*/
|
||||
static u32 dce_hsp_get_irq_sources(struct tegra_dce *d)
|
||||
{
|
||||
return (dce_hsp_ie_read(d, CCPLEX_HSP_IE) &
|
||||
dce_hsp_ir_read(d));
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_mailbox_isr - Isr for mailbox irqs.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
void dce_mailbox_isr(struct tegra_dce *d)
|
||||
{
|
||||
u8 i = 0;
|
||||
u32 value;
|
||||
struct dce_mailbox_interface *d_mb;
|
||||
u32 irq_sources = dce_hsp_get_irq_sources(d);
|
||||
|
||||
do {
|
||||
d_mb = &d->d_mb[i];
|
||||
/**
|
||||
* Get the mailbox on which the interrupt
|
||||
* is received.
|
||||
*/
|
||||
if (irq_sources & (BIT(d_mb->r_mb)
|
||||
<< DCE_MAILBOX_FULL_INT_SHIFT)) {
|
||||
/**
|
||||
* Read and store the value.
|
||||
*
|
||||
* TODO : Ignore the full interrupt
|
||||
* bit before storing the result.
|
||||
*
|
||||
*/
|
||||
value = dce_smb_read(d, d_mb->r_mb);
|
||||
dce_smb_set(d, 0U, d_mb->r_mb);
|
||||
dce_mailbox_store_interface_status(d, value, i);
|
||||
d_mb->notify(d, d_mb->notify_data);
|
||||
}
|
||||
i++;
|
||||
} while (i < DCE_MAILBOX_MAX_INTERFACES);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_mailbox_store_interface_status - stores the response
|
||||
* received on a mailbox interface.
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @v : Value to be stored.
|
||||
* @id : interface id.
|
||||
*
|
||||
* Return :Void
|
||||
*/
|
||||
void dce_mailbox_store_interface_status(struct tegra_dce *d, u32 v, u8 id)
|
||||
{
|
||||
struct dce_mailbox_interface *d_mb = &d->d_mb[id];
|
||||
|
||||
dce_mutex_lock(&d_mb->lock);
|
||||
d_mb->ack_value = v;
|
||||
d_mb->valid = true;
|
||||
dce_mutex_unlock(&d_mb->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_mailbox_get_interface_status - gets the response
|
||||
* received on mailbox interface.
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @id : Interface id.
|
||||
*
|
||||
* Return : u32 value
|
||||
*/
|
||||
u32 dce_mailbox_get_interface_status(struct tegra_dce *d, u8 id)
|
||||
{
|
||||
struct dce_mailbox_interface *d_mb = &d->d_mb[id];
|
||||
|
||||
if (d_mb->valid)
|
||||
return d_mb->ack_value;
|
||||
else
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_mailbox_invalidate_status - renders the response invalid.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @id : Interface id.
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
void dce_mailbox_invalidate_status(struct tegra_dce *d, u8 id)
|
||||
{
|
||||
struct dce_mailbox_interface *d_mb = &d->d_mb[id];
|
||||
|
||||
dce_mutex_lock(&d_mb->lock);
|
||||
d_mb->valid = false;
|
||||
dce_mutex_unlock(&d_mb->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_mailbox_write_safe - Checks if it's safe to write to
|
||||
* a mailbox register.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @id : Mailbox ID
|
||||
*
|
||||
* Return : true if it's safe
|
||||
*/
|
||||
static bool dce_mailbox_write_safe(struct tegra_dce *d, u8 id)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
val = dce_smb_read(d, id);
|
||||
|
||||
return !(val & BIT(31));
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_mailbox_set_full_interrupt - Sets the interrupt tag bit
|
||||
* in the mailbox register
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @id : Mailbox interface id.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
void dce_mailbox_set_full_interrupt(struct tegra_dce *d, u8 id)
|
||||
{
|
||||
struct dce_mailbox_interface *d_mb;
|
||||
|
||||
d_mb = &d->d_mb[id];
|
||||
|
||||
dce_mutex_lock(&d_mb->lock);
|
||||
|
||||
if (!dce_mailbox_write_safe(d, d_mb->s_mb))
|
||||
dce_info(d, "Intr bit set multiple times for MB : [0x%x]",
|
||||
d_mb->s_mb);
|
||||
|
||||
dce_smb_set(d, BIT(31), d_mb->s_mb);
|
||||
|
||||
dce_mutex_unlock(&d_mb->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_handle_mailbox_send_cmd_sync - handler function for
|
||||
* mailbox_send_cmd_sync
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @cmd : The command to be sent.
|
||||
* @interface : boot or admin interface
|
||||
*
|
||||
*
|
||||
* Return : 0 if successful.
|
||||
*/
|
||||
int dce_handle_mailbox_send_cmd_sync(struct tegra_dce *d, u32 cmd, u32 interface)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_mailbox_interface *d_mb;
|
||||
|
||||
d_mb = &d->d_mb[interface];
|
||||
|
||||
dce_mutex_lock(&d_mb->lock);
|
||||
|
||||
if (!dce_mailbox_write_safe(d, d_mb->s_mb)) {
|
||||
dce_err(d, "Previously sent message isn't synced");
|
||||
return -1;
|
||||
}
|
||||
|
||||
dce_smb_set(d, cmd | BIT(31), d_mb->s_mb);
|
||||
d_mb->valid = false;
|
||||
|
||||
dce_mutex_unlock(&d_mb->lock);
|
||||
|
||||
ret = d_mb->dce_mailbox_wait(d);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_mailbox_send_cmd_sync - Sends command via mailbox and waits for ack.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @cmd : The command to be sent.
|
||||
* @interface : boot or admin interface
|
||||
*
|
||||
* Return : 0 if successful.
|
||||
*/
|
||||
int dce_mailbox_send_cmd_sync(struct tegra_dce *d, u32 cmd, u32 interface)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_mailbox_send_cmd_params params;
|
||||
|
||||
params.cmd = cmd;
|
||||
params.interface = interface;
|
||||
|
||||
ret = dce_fsm_post_event(d, EVENT_ID_DCE_BOOT_CMD_MSG_REQUESTED,
|
||||
(void *)¶ms);
|
||||
if (ret) {
|
||||
dce_err(d, "Unable to send msg ret :%d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_mailbox_init_interface - Initializes the mailbox interface.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @id : Mailbox interface id.
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
int dce_mailbox_init_interface(struct tegra_dce *d, u8 id, u8 s_mb,
|
||||
u8 r_mb, int (*dce_mailbox_wait)(struct tegra_dce *),
|
||||
void *notify_data, void (*notify)(struct tegra_dce *, void *))
|
||||
{
|
||||
int ret;
|
||||
u64 ie_wr_val;
|
||||
struct dce_mailbox_interface *d_mb;
|
||||
|
||||
d_mb = &d->d_mb[id];
|
||||
|
||||
ret = dce_mutex_init(&d_mb->lock);
|
||||
if (ret) {
|
||||
dce_err(d, "dce lock initialization failed for mailbox");
|
||||
goto err_lock_init;
|
||||
}
|
||||
|
||||
d_mb->valid = false;
|
||||
|
||||
dce_smb_set_full_ie(d, true, r_mb);
|
||||
|
||||
ie_wr_val = BIT(r_mb) << 8U;
|
||||
dce_hsp_ie_write(d, ie_wr_val, CCPLEX_HSP_IE);
|
||||
|
||||
d_mb->s_mb = s_mb;
|
||||
d_mb->r_mb = r_mb;
|
||||
|
||||
d_mb->notify = notify;
|
||||
d_mb->notify_data = notify_data;
|
||||
|
||||
d_mb->dce_mailbox_wait
|
||||
= dce_mailbox_wait;
|
||||
|
||||
return 0;
|
||||
|
||||
err_lock_init:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_mailbox_deinit_interface - Releases the resources
|
||||
* associated with boot interface.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
void dce_mailbox_deinit_interface(struct tegra_dce *d, u8 id)
|
||||
{
|
||||
struct dce_mailbox_interface *d_mb;
|
||||
|
||||
d_mb = &d->d_mb[id];
|
||||
|
||||
dce_mutex_destroy(&d_mb->lock);
|
||||
}
|
||||
326
drivers/platform/tegra/dce/dce-module.c
Normal file
326
drivers/platform/tegra/dce/dce-module.c
Normal file
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* Copyright (c) 2019-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>
|
||||
#include <linux/of.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
/**
|
||||
* The following platform info is needed for backdoor
|
||||
* booting of dce.
|
||||
*/
|
||||
static const struct dce_platform_data t234_dce_platform_data = {
|
||||
.stream_id = 0x08,
|
||||
.phys_stream_id = 0x7f,
|
||||
.fw_carveout_id = 9,
|
||||
.hsp_id = 0x0,
|
||||
.fw_vmindex = 0,
|
||||
.fw_name = "display-t234-dce.bin",
|
||||
.fw_dce_addr = 0x40000000,
|
||||
.fw_info_valid = true,
|
||||
.use_physical_id = false,
|
||||
};
|
||||
|
||||
__weak const struct of_device_id tegra_dce_of_match[] = {
|
||||
{
|
||||
.compatible = "nvidia,tegra234-dce",
|
||||
.data = (struct dce_platform_data *)&t234_dce_platform_data
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tegra_dce_of_match);
|
||||
|
||||
/**
|
||||
* dce_get_pdata_dce - inline function to get the tegra_dce pointer
|
||||
* from platform devicve.
|
||||
*
|
||||
* @pdev : Pointer to the platform device data structure.
|
||||
*
|
||||
* Return : Pointer pointing to tegra_dce data structure.
|
||||
*/
|
||||
static inline struct tegra_dce *dce_get_pdata_dce(struct platform_device *pdev)
|
||||
{
|
||||
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.
|
||||
*
|
||||
* @pdev : Pointer to Linux's platform device used for registering DCE.
|
||||
*
|
||||
* Primarily used during initialization sequence and is expected to be called
|
||||
* from probe only.
|
||||
*
|
||||
* Return : 0 if success else the corresponding error value.
|
||||
*/
|
||||
static int dce_init_dev_data(struct platform_device *pdev, struct dce_platform_data *pdata)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dce_device *d_dev = NULL;
|
||||
|
||||
d_dev = devm_kzalloc(dev, sizeof(*d_dev), GFP_KERNEL);
|
||||
if (!d_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
d_dev->dev = dev;
|
||||
d_dev->pdata = pdata;
|
||||
d_dev->regs = of_iomap(dev->of_node, 0);
|
||||
if (!d_dev->regs) {
|
||||
dev_err(dev, "failed to map dce cluster IO space\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev, d_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_isr - Handles dce interrupts
|
||||
*/
|
||||
static irqreturn_t dce_isr(int irq, void *data)
|
||||
{
|
||||
struct tegra_dce *d = data;
|
||||
|
||||
dce_mailbox_isr(d);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void dce_set_irqs(struct platform_device *pdev, bool en)
|
||||
{
|
||||
int i = 0;
|
||||
struct tegra_dce *d;
|
||||
struct dce_device *d_dev = NULL;
|
||||
|
||||
d_dev = dev_get_drvdata(&pdev->dev);
|
||||
d = dce_get_pdata_dce(pdev);
|
||||
|
||||
for (i = 0; i < d_dev->max_cpu_irqs; i++) {
|
||||
if (en)
|
||||
enable_irq(d->irq[i]);
|
||||
else
|
||||
disable_irq(d->irq[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_req_interrupts - function to initialize CPU irqs for DCE cpu driver.
|
||||
*
|
||||
* @pdev : Pointet to Dce Linux Platform Device.
|
||||
*
|
||||
* Return : 0 if success else the corresponding error value.
|
||||
*/
|
||||
static int dce_req_interrupts(struct platform_device *pdev)
|
||||
{
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
int no_ints = 0;
|
||||
struct tegra_dce *d;
|
||||
struct dce_device *d_dev = NULL;
|
||||
|
||||
d_dev = dev_get_drvdata(&pdev->dev);
|
||||
d = dce_get_pdata_dce(pdev);
|
||||
|
||||
no_ints = platform_irq_count(pdev);
|
||||
if (no_ints == 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"Invalid number of interrupts configured = %d",
|
||||
no_ints);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
d_dev->max_cpu_irqs = no_ints;
|
||||
|
||||
for (i = 0; i < no_ints; i++) {
|
||||
ret = platform_get_irq(pdev, i);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"Getting dce intr lines failed with ret = %d",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
d->irq[i] = ret;
|
||||
ret = devm_request_threaded_irq(&pdev->dev, d->irq[i],
|
||||
NULL, dce_isr, IRQF_ONESHOT, "tegra_dce_isr",
|
||||
d);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to request irq @ with ret = %d\n",
|
||||
ret);
|
||||
}
|
||||
disable_irq(d->irq[i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int match_display_dev(struct device *dev, const void *data)
|
||||
{
|
||||
if ((dev != NULL) && (dev->of_node != NULL)) {
|
||||
if (of_device_is_compatible(dev->of_node, "nvidia,tegra234-display"))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_dce_probe(struct platform_device *pdev)
|
||||
{
|
||||
int err = 0;
|
||||
struct tegra_dce *d = NULL;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dce_platform_data *pdata = NULL;
|
||||
const struct of_device_id *match = NULL;
|
||||
struct device *c_dev;
|
||||
struct device_link *link;
|
||||
|
||||
match = of_match_device(tegra_dce_of_match, dev);
|
||||
if (!match) {
|
||||
dev_info(dev, "no device match found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pdata = (struct dce_platform_data *)match->data;
|
||||
|
||||
WARN_ON(!pdata);
|
||||
if (!pdata) {
|
||||
dev_info(dev, "no platform data\n");
|
||||
err = -ENODATA;
|
||||
goto err_get_pdata;
|
||||
}
|
||||
|
||||
err = dce_init_dev_data(pdev, pdata);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to init device data with err = %d\n",
|
||||
err);
|
||||
goto os_init_err;
|
||||
}
|
||||
|
||||
err = dce_req_interrupts(pdev);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to get interrupts with err = %d\n",
|
||||
err);
|
||||
goto req_intr_err;
|
||||
}
|
||||
|
||||
d = dce_get_pdata_dce(pdev);
|
||||
|
||||
/**
|
||||
* TODO: Get HSP_ID from DT
|
||||
*/
|
||||
d->hsp_id = pdata->hsp_id;
|
||||
|
||||
|
||||
err = dce_driver_init(d);
|
||||
if (err) {
|
||||
dce_err(d, "DCE Driver Init Failed");
|
||||
goto err_driver_init;
|
||||
}
|
||||
|
||||
dce_set_irqs(pdev, true);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
dce_init_debug(d);
|
||||
#endif
|
||||
|
||||
c_dev = bus_find_device(&platform_bus_type, NULL, NULL, match_display_dev);
|
||||
if (c_dev != NULL) {
|
||||
dce_info(d, "Found display consumer device");
|
||||
link = device_link_add(c_dev, dev,
|
||||
DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_SUPPLIER);
|
||||
if (link == NULL) {
|
||||
dce_err(d, "Failed to create device link to %s\n", dev_name(c_dev));
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
req_intr_err:
|
||||
os_init_err:
|
||||
err_get_pdata:
|
||||
err_driver_init:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int tegra_dce_remove(struct platform_device *pdev)
|
||||
{
|
||||
/* TODO */
|
||||
struct tegra_dce *d =
|
||||
dce_get_pdata_dce(pdev);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
dce_remove_debug(d);
|
||||
#endif
|
||||
|
||||
dce_set_irqs(pdev, false);
|
||||
dce_driver_deinit(d);
|
||||
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);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops dce_pm_ops = {
|
||||
.suspend = dce_pm_suspend,
|
||||
.resume = dce_pm_resume,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct platform_driver tegra_dce_driver = {
|
||||
.driver = {
|
||||
.name = "tegra-dce",
|
||||
.of_match_table =
|
||||
of_match_ptr(tegra_dce_of_match),
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &dce_pm_ops,
|
||||
#endif
|
||||
},
|
||||
.probe = tegra_dce_probe,
|
||||
.remove = tegra_dce_remove,
|
||||
};
|
||||
module_platform_driver(tegra_dce_driver);
|
||||
|
||||
MODULE_DESCRIPTION("DCE Linux driver");
|
||||
MODULE_AUTHOR("NVIDIA");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
178
drivers/platform/tegra/dce/dce-pm.c
Normal file
178
drivers/platform/tegra/dce/dce-pm.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
dce_set_boot_complete(d, false);
|
||||
d->boot_status |= DCE_FW_SUSPENDED;
|
||||
|
||||
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;
|
||||
}
|
||||
81
drivers/platform/tegra/dce/dce-reset.c
Normal file
81
drivers/platform/tegra/dce/dce-reset.c
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020, NVIDIA CORPORATION. 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>
|
||||
#include <dce-log.h>
|
||||
#include <dce-util-common.h>
|
||||
|
||||
enum pm_controls {
|
||||
FW_LOAD_HALTED,
|
||||
FW_LOAD_DONE
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_evp_set_reset_addr - Writes to the evp reset addr register.
|
||||
*
|
||||
* @d : Pointer to struct tegra_dce
|
||||
* @addr : 32bit address
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static inline void dce_evp_set_reset_addr(struct tegra_dce *d, u32 addr)
|
||||
{
|
||||
dce_writel(d, evp_reset_addr_r(), addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_pm_set_pm_ctrl - Writes to the reset control register.
|
||||
*
|
||||
* @d : Pointer to struct tegra_dce
|
||||
* @val : Value to programmed to the register
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dce_pm_set_pm_ctrl(struct tegra_dce *d, enum pm_controls val)
|
||||
{
|
||||
switch (val) {
|
||||
case FW_LOAD_DONE:
|
||||
dce_writel(d, pm_r5_ctrl_r(), pm_r5_ctrl_fwloaddone_done_f());
|
||||
break;
|
||||
case FW_LOAD_HALTED:
|
||||
dce_writel(d, pm_r5_ctrl_r(), pm_r5_ctrl_fwloaddone_halted_f());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_reset_dce - Configures the pertinent registers in
|
||||
* DCE cluser to reset DCE.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : 0 if success
|
||||
*/
|
||||
int dce_reset_dce(struct tegra_dce *d)
|
||||
{
|
||||
u32 fw_dce_addr;
|
||||
|
||||
if (!d->fw_data) {
|
||||
dce_err(d, "No fw_data present");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fw_dce_addr = dce_get_fw_dce_addr(d);
|
||||
dce_evp_set_reset_addr(d, fw_dce_addr);
|
||||
|
||||
dce_pm_set_pm_ctrl(d, FW_LOAD_DONE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
660
drivers/platform/tegra/dce/dce-util-common.c
Normal file
660
drivers/platform/tegra/dce/dce-util-common.c
Normal file
@@ -0,0 +1,660 @@
|
||||
/*
|
||||
* Copyright (c) 2019-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>
|
||||
#include <dce-util-common.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/firmware.h>
|
||||
|
||||
/**
|
||||
* dce_writel - Dce io function to perform MMIO writes
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @r : register offset from dce_base.
|
||||
* @v : value to be written
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
void dce_writel(struct tegra_dce *d, u32 r, u32 v)
|
||||
{
|
||||
struct dce_device *d_dev = dce_device_from_dce(d);
|
||||
|
||||
if (unlikely(!d_dev->regs))
|
||||
dce_err(d, "DCE Register Space not IOMAPed to CPU");
|
||||
else
|
||||
writel(v, d_dev->regs + r);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_readl - Dce io function to perform MMIO reads
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @r : register offset from dce_base.
|
||||
*
|
||||
* Return : the read value
|
||||
*/
|
||||
u32 dce_readl(struct tegra_dce *d, u32 r)
|
||||
{
|
||||
u32 v = 0xffffffff;
|
||||
|
||||
struct dce_device *d_dev = dce_device_from_dce(d);
|
||||
|
||||
if (unlikely(!d_dev->regs))
|
||||
dce_err(d, "DCE Register Space not IOMAPed to CPU");
|
||||
else
|
||||
v = readl(d_dev->regs + r);
|
||||
/*TODO : Add error check here */
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_writel_check - Performs MMIO writes and checks if the writes
|
||||
* are actaully correct.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @r : register offset from dce_base.
|
||||
* @v : value to be written
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
void dce_writel_check(struct tegra_dce *d, u32 r, u32 v)
|
||||
{
|
||||
/* TODO : Write and read back to check */
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_io_exists - Dce io function to check if the registers are mapped
|
||||
* to CPU correctly
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : True if mapped.
|
||||
*/
|
||||
bool dce_io_exists(struct tegra_dce *d)
|
||||
{
|
||||
struct dce_device *d_dev = dce_device_from_dce(d);
|
||||
|
||||
return d_dev->regs != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_io_valid_regs - Dce io function to check if the requested offset is
|
||||
* within the range of CPU mapped MMIO range.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @r : register offset from dce_base.
|
||||
*
|
||||
* Return : True if offset within range.
|
||||
*/
|
||||
bool dce_io_valid_reg(struct tegra_dce *d, u32 r)
|
||||
{
|
||||
/* TODO : Implement range check here. Returning true for now*/
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_kzalloc - Function to allocate contiguous kernel memory
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @size_t : Size of the memory to be allocated
|
||||
* @dma_flag: True if allocated memory should be DMAable
|
||||
*
|
||||
* Return : CPU Mapped Address if successful else NULL.
|
||||
*/
|
||||
void *dce_kzalloc(struct tegra_dce *d, size_t size, bool dma_flag)
|
||||
{
|
||||
void *alloc;
|
||||
gfp_t flags = GFP_KERNEL;
|
||||
|
||||
if (dma_flag)
|
||||
flags |= __GFP_DMA;
|
||||
|
||||
alloc = kzalloc(size, flags);
|
||||
|
||||
return alloc;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_kfree - Frees an alloc from dce_kzalloc
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @addr : Address of the object to free.
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
void dce_kfree(struct tegra_dce *d, void *addr)
|
||||
{
|
||||
kfree(addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_request_firmware - Reads the fw into memory.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @fw_name : Name of the fw.
|
||||
*
|
||||
* Return : Pointer to dce_firmware if successful else NULL.
|
||||
*/
|
||||
struct dce_firmware *dce_request_firmware(struct tegra_dce *d,
|
||||
const char *fw_name)
|
||||
{
|
||||
struct device *dev = dev_from_dce(d);
|
||||
struct dce_firmware *fw;
|
||||
const struct firmware *l_fw;
|
||||
|
||||
fw = dce_kzalloc(d, sizeof(*fw), false);
|
||||
if (!fw)
|
||||
return NULL;
|
||||
|
||||
if (request_firmware(&l_fw, fw_name, dev) < 0) {
|
||||
dce_err(d, "FW Request Failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!l_fw)
|
||||
goto err;
|
||||
|
||||
/* Make sure the address is aligned to 4K */
|
||||
fw->size = l_fw->size;
|
||||
|
||||
fw->size = ALIGN(fw->size + SZ_4K, SZ_4K);
|
||||
/**
|
||||
* BUG : Currently overwriting all alignment logic above to blinldy
|
||||
* allocate 2MB FW virtual space. Ideally it should be as per the
|
||||
* actual size of the fw.
|
||||
*/
|
||||
fw->size = SZ_32M;
|
||||
|
||||
fw->data = dma_alloc_coherent(dev, fw->size,
|
||||
(dma_addr_t *)&fw->dma_handle,
|
||||
GFP_KERNEL);
|
||||
if (!fw->data)
|
||||
goto err_release;
|
||||
|
||||
memcpy((u8 *)fw->data, (u8 *)l_fw->data, l_fw->size);
|
||||
|
||||
release_firmware(l_fw);
|
||||
|
||||
return fw;
|
||||
|
||||
err_release:
|
||||
release_firmware(l_fw);
|
||||
err:
|
||||
dce_kfree(d, fw);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_release_firmware - Reads the fw into memory.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @fw : Pointer to dce_firmware.
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
void dce_release_fw(struct tegra_dce *d, struct dce_firmware *fw)
|
||||
{
|
||||
struct device *dev = dev_from_dce(d);
|
||||
|
||||
if (!fw)
|
||||
return;
|
||||
|
||||
dma_free_coherent(dev, fw->size,
|
||||
(void *)fw->data,
|
||||
(dma_addr_t)fw->dma_handle);
|
||||
|
||||
dce_kfree(d, fw);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_get_phys_stream_id - Gets the physical stream ID to be programmed from
|
||||
* platform data.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : Stream ID Value
|
||||
*/
|
||||
u8 dce_get_phys_stream_id(struct tegra_dce *d)
|
||||
{
|
||||
return pdata_from_dce(d)->phys_stream_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_get_dce_stream_id - Gets the dce stream ID to be programmed from
|
||||
* platform data.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : Stream ID Value
|
||||
*/
|
||||
u8 dce_get_dce_stream_id(struct tegra_dce *d)
|
||||
{
|
||||
return pdata_from_dce(d)->stream_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_get_fw_vm_index - Gets the VMIndex for the fw region to be
|
||||
* programmed from platform data.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : VMIndex
|
||||
*/
|
||||
u8 dce_get_fw_vm_index(struct tegra_dce *d)
|
||||
{
|
||||
return pdata_from_dce(d)->fw_vmindex;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_get_fw_carveout_id- Gets the carveout ID for the fw region to be
|
||||
* programmed from platform data.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : Carveout Id
|
||||
*/
|
||||
u8 dce_get_fw_carveout_id(struct tegra_dce *d)
|
||||
{
|
||||
return pdata_from_dce(d)->fw_carveout_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_is_physical_id_valid - Checks if the DCE can use physical stream ID.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : True if SMMU is disabled.
|
||||
*/
|
||||
bool dce_is_physical_id_valid(struct tegra_dce *d)
|
||||
{
|
||||
return pdata_from_dce(d)->use_physical_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_get_fw_dce_addr - Gets the 32bit address to be used for
|
||||
* loading the fw before being converted
|
||||
* by AST into a 40-bit address.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : 32bit address
|
||||
*/
|
||||
u32 dce_get_fw_dce_addr(struct tegra_dce *d)
|
||||
{
|
||||
return pdata_from_dce(d)->fw_dce_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_get_fw_phy_addr - Gets the 40bit address to be used by AST
|
||||
* for loading the fw after converting
|
||||
* the 32bit incoming address.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* This API is to be used only if the memory is being allocated
|
||||
* via kzalloc or friends. Do not use this if memory is
|
||||
* allocated via dma apis.
|
||||
*
|
||||
* Return : 64bit address
|
||||
*/
|
||||
u64 dce_get_fw_phy_addr(struct tegra_dce *d, struct dce_firmware *fw)
|
||||
{
|
||||
/* Caller should make sure that *fw is valid since this func is
|
||||
* not expected to return any error.
|
||||
*/
|
||||
return (u64)virt_to_phys((void *)fw->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_get_fw_name - Gets the dce fw name from platform data.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : fw_name
|
||||
*/
|
||||
const char *dce_get_fw_name(struct tegra_dce *d)
|
||||
{
|
||||
return pdata_from_dce(d)->fw_name;
|
||||
}
|
||||
|
||||
static void dce_print(const char *func_name, int line,
|
||||
enum dce_log_type type, const char *log)
|
||||
{
|
||||
#define DCE_LOG_FMT "dce: %15s:%-4d %s\n"
|
||||
|
||||
switch (type) {
|
||||
case DCE_DEBUG:
|
||||
pr_debug(DCE_LOG_FMT, func_name, line, log);
|
||||
break;
|
||||
case DCE_INFO:
|
||||
pr_info(DCE_LOG_FMT, func_name, line, log);
|
||||
break;
|
||||
case DCE_WARNING:
|
||||
pr_warn(DCE_LOG_FMT, func_name, line, log);
|
||||
break;
|
||||
case DCE_ERROR:
|
||||
pr_err(DCE_LOG_FMT, func_name, line, log);
|
||||
break;
|
||||
}
|
||||
#undef DCE_LOG_FMT
|
||||
}
|
||||
|
||||
__printf(5, 6)
|
||||
void dce_log_msg(struct tegra_dce *d, const char *func_name, int line,
|
||||
enum dce_log_type type, const char *fmt, ...)
|
||||
{
|
||||
|
||||
#define BUF_LEN 100
|
||||
|
||||
char log[BUF_LEN];
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
(void) vsnprintf(log, BUF_LEN, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
dce_print(func_name, line, type, log);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_cond_init - Initialize a condition variable
|
||||
*
|
||||
* @cond - The condition variable to initialize
|
||||
*
|
||||
* Initialize a condition variable before using it.
|
||||
*/
|
||||
int dce_cond_init(struct dce_cond *cond)
|
||||
{
|
||||
init_waitqueue_head(&cond->wq);
|
||||
cond->initialized = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_cond_destroy - Destroy a condition variable
|
||||
*
|
||||
* @cond - The condition variable to destroy
|
||||
*/
|
||||
void dce_cond_destroy(struct dce_cond *cond)
|
||||
{
|
||||
cond->initialized = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_cond_signal - Signal a condition variable
|
||||
*
|
||||
* @cond - The condition variable to signal
|
||||
*
|
||||
* Wake up a waiter for a condition variable to check if its condition has been
|
||||
* satisfied.
|
||||
*
|
||||
* The waiter is using an uninterruptible wait.
|
||||
*/
|
||||
void dce_cond_signal(struct dce_cond *cond)
|
||||
{
|
||||
WARN_ON(!cond->initialized);
|
||||
|
||||
wake_up(&cond->wq);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_cond_signal_interruptible - Signal a condition variable
|
||||
*
|
||||
* @cond - The condition variable to signal
|
||||
*
|
||||
* Wake up a waiter for a condition variable to check if its condition has been
|
||||
* satisfied.
|
||||
*
|
||||
* The waiter is using an interruptible wait.
|
||||
*/
|
||||
void dce_cond_signal_interruptible(struct dce_cond *cond)
|
||||
{
|
||||
WARN_ON(!cond->initialized);
|
||||
|
||||
wake_up_interruptible(&cond->wq);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_cond_broadcast - Signal all waiters of a condition variable
|
||||
*
|
||||
* @cond - The condition variable to signal
|
||||
*
|
||||
* Wake up all waiters for a condition variable to check if their conditions
|
||||
* have been satisfied.
|
||||
*
|
||||
* The waiters are using an uninterruptible wait.
|
||||
*/
|
||||
int dce_cond_broadcast(struct dce_cond *cond)
|
||||
{
|
||||
if (!cond->initialized)
|
||||
return -EINVAL;
|
||||
|
||||
wake_up_all(&cond->wq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_cond_broadcast_interruptible - Signal all waiters of a condition
|
||||
* variable
|
||||
*
|
||||
* @cond - The condition variable to signal
|
||||
*
|
||||
* Wake up all waiters for a condition variable to check if their conditions
|
||||
* have been satisfied.
|
||||
*
|
||||
* The waiters are using an interruptible wait.
|
||||
*/
|
||||
int dce_cond_broadcast_interruptible(struct dce_cond *cond)
|
||||
{
|
||||
if (!cond->initialized)
|
||||
return -EINVAL;
|
||||
|
||||
wake_up_interruptible_all(&cond->wq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_thread_proxy - Function to be passed to kthread.
|
||||
*
|
||||
* @thread_data : Pointer to actual dce_thread struct
|
||||
*
|
||||
* Return : Ruturns the return value of the function to be run.
|
||||
*/
|
||||
static int dce_thread_proxy(void *thread_data)
|
||||
{
|
||||
struct dce_thread *thread = thread_data;
|
||||
int ret = thread->fn(thread->data);
|
||||
|
||||
thread->running = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_thread_create - Create and run a new thread.
|
||||
*
|
||||
* @thread - thread structure to use
|
||||
* @data - data to pass to threadfn
|
||||
* @threadfn - Thread function
|
||||
* @name - name of the thread
|
||||
*
|
||||
* Create a thread and run threadfn in it. The thread stays alive as long as
|
||||
* threadfn is running. As soon as threadfn returns the thread is destroyed.
|
||||
*
|
||||
* threadfn needs to continuously poll dce_thread_should_stop() to determine
|
||||
* if it should exit.
|
||||
*/
|
||||
int dce_thread_create(struct dce_thread *thread,
|
||||
void *data,
|
||||
int (*threadfn)(void *data), const char *name)
|
||||
{
|
||||
struct task_struct *task = kthread_create(dce_thread_proxy,
|
||||
thread, name);
|
||||
if (IS_ERR(task))
|
||||
return PTR_ERR(task);
|
||||
|
||||
thread->task = task;
|
||||
thread->fn = threadfn;
|
||||
thread->data = data;
|
||||
thread->running = true;
|
||||
wake_up_process(task);
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_thread_stop - Destroy or request to destroy a thread
|
||||
*
|
||||
* @thread - thread to stop
|
||||
*
|
||||
* Request a thread to stop by setting dce_thread_should_stop() to
|
||||
* true and wait for thread to exit.
|
||||
*/
|
||||
void dce_thread_stop(struct dce_thread *thread)
|
||||
{
|
||||
/*
|
||||
* Threads waiting on wq's should have dce_thread_should_stop()
|
||||
* as one of its wakeup condition. This allows the thread to be woken
|
||||
* up when kthread_stop() is invoked and does not require an additional
|
||||
* callback to wakeup the sleeping thread.
|
||||
*/
|
||||
if (thread->task) {
|
||||
kthread_stop(thread->task);
|
||||
thread->task = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_thread_should_stop - Query if thread should stop
|
||||
*
|
||||
* @thread
|
||||
*
|
||||
* Return true if thread should exit. Can be run only in the thread's own
|
||||
* context and with the thread as parameter.
|
||||
*/
|
||||
bool dce_thread_should_stop(struct dce_thread *thread)
|
||||
{
|
||||
return kthread_should_stop();
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_thread_is_running - Query if thread is running
|
||||
*
|
||||
* @thread
|
||||
*
|
||||
* Return true if thread is started.
|
||||
*/
|
||||
bool dce_thread_is_running(struct dce_thread *thread)
|
||||
{
|
||||
return READ_ONCE(thread->running);
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_thread_join - join a thread to reclaim resources
|
||||
* after it has exited
|
||||
*
|
||||
* @thread - thread to join
|
||||
*
|
||||
*/
|
||||
void dce_thread_join(struct dce_thread *thread)
|
||||
{
|
||||
while (READ_ONCE(thread->running))
|
||||
usleep_range(10000, 20000);
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_get_nxt_pow_of_2 : get next power of 2 number for a given number
|
||||
*
|
||||
* @addr : Address of given number
|
||||
* @nbits : bits in given number
|
||||
*
|
||||
* Return : unsigned long next power of 2 value
|
||||
*/
|
||||
unsigned long dce_get_nxt_pow_of_2(unsigned long *addr, u8 nbits)
|
||||
{
|
||||
u8 l_bit = 0;
|
||||
u8 bit_index = 0;
|
||||
unsigned long val;
|
||||
|
||||
val = *addr;
|
||||
if (val == 0)
|
||||
return 0;
|
||||
|
||||
bit_index = find_first_bit(addr, nbits);
|
||||
|
||||
while (bit_index && (bit_index < nbits)) {
|
||||
l_bit = bit_index;
|
||||
bit_index = find_next_bit(addr, nbits, bit_index + 1);
|
||||
}
|
||||
|
||||
if (BIT(l_bit) < val) {
|
||||
l_bit += 1UL;
|
||||
val = BIT(l_bit);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* dce_schedule_work : schedule work in global highpri workqueue
|
||||
*
|
||||
* @work : dce work to be scheduled
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
void dce_schedule_work(struct dce_work_struct *work)
|
||||
{
|
||||
queue_work(system_highpri_wq, &work->work);
|
||||
}
|
||||
|
||||
/*
|
||||
* dce_work_handle_fn : handler function for scheduled dce-work
|
||||
*
|
||||
* @work : Pointer to the scheduled work
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
static void dce_work_handle_fn(struct work_struct *work)
|
||||
{
|
||||
struct dce_work_struct *dce_work = container_of(work,
|
||||
struct dce_work_struct,
|
||||
work);
|
||||
|
||||
if (dce_work->dce_work_fn != NULL)
|
||||
dce_work->dce_work_fn(dce_work->d);
|
||||
}
|
||||
|
||||
/*
|
||||
* dce_init_work : Init dce work structure
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @work : Pointer to dce work structure
|
||||
* @work_fn : worker function to be called
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
int dce_init_work(struct tegra_dce *d,
|
||||
struct dce_work_struct *work,
|
||||
void (*work_fn)(struct tegra_dce *d))
|
||||
{
|
||||
work->d = d;
|
||||
work->dce_work_fn = work_fn;
|
||||
|
||||
INIT_WORK(&work->work, dce_work_handle_fn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
162
drivers/platform/tegra/dce/dce-worker.c
Normal file
162
drivers/platform/tegra/dce/dce-worker.c
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 2019-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>
|
||||
#include <dce-cond.h>
|
||||
#include <dce-lock.h>
|
||||
#include <dce-worker.h>
|
||||
#include <dce-util-common.h>
|
||||
#include <interface/dce-admin-cmds.h>
|
||||
|
||||
/*
|
||||
* dce_wait_interruptible : Wait for a given condition
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @msg_id : index of wait condition
|
||||
*
|
||||
* Return : 0 if successful else error code
|
||||
*/
|
||||
int dce_wait_interruptible(struct tegra_dce *d, u32 msg_id)
|
||||
{
|
||||
struct dce_wait_cond *wait;
|
||||
|
||||
if (msg_id >= DCE_MAX_WAIT) {
|
||||
dce_err(d, "Invalid wait requested %u", msg_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wait = &d->ipc_waits[msg_id];
|
||||
|
||||
/*
|
||||
* It is possible that we received the ACK from DCE even before we
|
||||
* start waiting. But that should not be an issue as wait->complete
|
||||
* Will be "1" and we immediately exit from the wait.
|
||||
*/
|
||||
DCE_COND_WAIT_INTERRUPTIBLE(&wait->cond_wait,
|
||||
atomic_read(&wait->complete) == 1);
|
||||
|
||||
if (atomic_read(&wait->complete) != 1)
|
||||
return -EINTR;
|
||||
|
||||
/*
|
||||
* Clear wait->complete as soon as we exit from wait (consume the wake call)
|
||||
* So that when the next dce_wait_interruptible is called, it doesn't see old
|
||||
* wait->complete state.
|
||||
*/
|
||||
atomic_set(&wait->complete, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* dce_wakeup_interruptible : Wakeup waiting task on given condition
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @msg_id : index of wait condition
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
void dce_wakeup_interruptible(struct tegra_dce *d, u32 msg_id)
|
||||
{
|
||||
struct dce_wait_cond *wait;
|
||||
|
||||
if (msg_id >= DCE_MAX_WAIT) {
|
||||
dce_err(d, "Invalid wait requested %u", msg_id);
|
||||
return;
|
||||
}
|
||||
|
||||
wait = &d->ipc_waits[msg_id];
|
||||
|
||||
/*
|
||||
* Set wait->complete to "1", so if the wait is called even after
|
||||
* "dce_cond_signal_interruptible", it'll see the complete variable
|
||||
* as "1" and exit the wait immediately.
|
||||
*/
|
||||
atomic_set(&wait->complete, 1);
|
||||
dce_cond_signal_interruptible(&wait->cond_wait);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_work_cond_sw_resource_init : Init dce workqueues related resources
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : 0 if successful else error code
|
||||
*/
|
||||
int dce_work_cond_sw_resource_init(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
ret = dce_init_work(d, &d->dce_bootstrap_work, dce_bootstrap_work_fn);
|
||||
if (ret) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (dce_cond_init(&d->dce_bootstrap_done)) {
|
||||
dce_err(d, "dce boot wait condition init failed");
|
||||
ret = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (i = 0; i < DCE_MAX_WAIT; i++) {
|
||||
struct dce_wait_cond *wait = &d->ipc_waits[i];
|
||||
|
||||
if (dce_cond_init(&wait->cond_wait)) {
|
||||
dce_err(d, "dce wait condition %d init failed", i);
|
||||
ret = -1;
|
||||
goto init_error;
|
||||
}
|
||||
|
||||
atomic_set(&wait->complete, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
init_error:
|
||||
while (i >= 0) {
|
||||
struct dce_wait_cond *wait = &d->ipc_waits[i];
|
||||
|
||||
dce_cond_destroy(&wait->cond_wait);
|
||||
i--;
|
||||
}
|
||||
dce_cond_destroy(&d->dce_bootstrap_done);
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_work_cond_sw_resource_deinit : de-init dce workqueues related resources
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
void dce_work_cond_sw_resource_deinit(struct tegra_dce *d)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < DCE_MAX_WAIT; i++) {
|
||||
struct dce_wait_cond *wait = &d->ipc_waits[i];
|
||||
|
||||
dce_cond_destroy(&wait->cond_wait);
|
||||
atomic_set(&wait->complete, 0);
|
||||
}
|
||||
|
||||
dce_cond_destroy(&d->dce_bootstrap_done);
|
||||
}
|
||||
71
drivers/platform/tegra/dce/include/dce-client-ipc-internal.h
Normal file
71
drivers/platform/tegra/dce/include/dce-client-ipc-internal.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2022, NVIDIA CORPORATION. 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_CLIENT_IPC_INTERNAL_H
|
||||
#define DCE_CLIENT_IPC_INTERNAL_H
|
||||
|
||||
#include <linux/platform/tegra/dce/dce-client-ipc.h>
|
||||
|
||||
/**
|
||||
* struct tegra_dce_client_ipc - Data Structure to hold client specific ipc
|
||||
* data pertaining to IPC type
|
||||
*
|
||||
* @valid : Tells if the client ipc data held by data structure is valid
|
||||
* @data : Pointer to any specific data passed by client during registration
|
||||
* for corresponding IPC type
|
||||
* @type : Corresponding IPC type as defined in CPU driver
|
||||
* @handle : Corresponding handle allocated for client during registration
|
||||
* @int_type : IPC interface type for above IPC type as defined in CPU driver
|
||||
* @d : pointer to OS agnostic dce struct. Stores all runtime info for dce
|
||||
* cluster elements
|
||||
* @recv_wait : condition variable used for IPC synchronization
|
||||
* @complete : atomic variable used for IPC synchronization
|
||||
* @callback_fn : function pointer to the callback function passed by the
|
||||
* client during registration
|
||||
*/
|
||||
struct tegra_dce_client_ipc {
|
||||
bool valid;
|
||||
void *data;
|
||||
uint32_t type;
|
||||
uint32_t handle;
|
||||
uint32_t int_type;
|
||||
struct tegra_dce *d;
|
||||
struct dce_cond recv_wait;
|
||||
atomic_t complete;
|
||||
tegra_dce_client_ipc_callback_t callback_fn;
|
||||
};
|
||||
|
||||
#define DCE_MAX_ASYNC_WORK 8
|
||||
struct dce_async_work {
|
||||
struct tegra_dce *d;
|
||||
struct work_struct async_event_work;
|
||||
atomic_t in_use;
|
||||
};
|
||||
|
||||
/**
|
||||
* @async_event_wq - Workqueue to process async events from DCE
|
||||
*/
|
||||
struct tegra_dce_async_ipc_info {
|
||||
struct workqueue_struct *async_event_wq;
|
||||
struct dce_async_work work[DCE_MAX_ASYNC_WORK];
|
||||
};
|
||||
|
||||
void dce_client_ipc_wakeup(struct tegra_dce *d, u32 ch_type);
|
||||
|
||||
int dce_client_ipc_wait(struct tegra_dce *d, u32 ch_type);
|
||||
|
||||
int dce_client_init(struct tegra_dce *d);
|
||||
|
||||
void dce_client_deinit(struct tegra_dce *d);
|
||||
|
||||
#endif
|
||||
133
drivers/platform/tegra/dce/include/dce-cond.h
Normal file
133
drivers/platform/tegra/dce/include/dce-cond.h
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2022, NVIDIA CORPORATION. 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_COND_H
|
||||
#define DCE_COND_H
|
||||
|
||||
#include <linux/wait.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
struct dce_cond {
|
||||
bool initialized;
|
||||
wait_queue_head_t wq;
|
||||
};
|
||||
|
||||
/**
|
||||
* DCE_COND_WAIT - Wait for a condition to be true
|
||||
*
|
||||
* @c - The condition variable to sleep on
|
||||
* @condition - The condition that needs to be true
|
||||
*
|
||||
* Wait for a condition to become true.
|
||||
*/
|
||||
#define DCE_COND_WAIT(c, condition) \
|
||||
({\
|
||||
int ret = 0; \
|
||||
wait_event((c)->wq, condition); \
|
||||
ret;\
|
||||
})
|
||||
|
||||
/**
|
||||
* DCE_COND_WAIT_INTERRUPTIBLE - Wait for a condition to be true
|
||||
*
|
||||
* @c - The condition variable to sleep on
|
||||
* @condition - The condition that needs to be true
|
||||
*
|
||||
* Wait for a condition to become true. Returns -ERESTARTSYS
|
||||
* on signal.
|
||||
*/
|
||||
#define DCE_COND_WAIT_INTERRUPTIBLE(c, condition) \
|
||||
({ \
|
||||
int ret = 0; \
|
||||
ret = wait_event_interruptible((c)->wq, condition); \
|
||||
ret; \
|
||||
})
|
||||
|
||||
/**
|
||||
* DCE_COND_WAIT_TIMEOUT - Wait for a condition to be true
|
||||
*
|
||||
* @c - The condition variable to sleep on
|
||||
* @condition - The condition that needs to be true
|
||||
* @timeout_ms - Timeout in milliseconds, or 0 for infinite wait.
|
||||
* This parameter must be a u32. Since this is a macro, this is
|
||||
* enforced by assigning a typecast NULL pointer to a u32 tmp
|
||||
* variable which will generate a compiler warning (or error if
|
||||
* the warning is configured as an error).
|
||||
*
|
||||
* Wait for a condition to become true. Returns -ETIMEOUT if
|
||||
* the wait timed out with condition false.
|
||||
*/
|
||||
#define DCE_COND_WAIT_TIMEOUT(c, condition, timeout_ms) \
|
||||
({\
|
||||
int ret = 0; \
|
||||
/* This is the assignment to enforce a u32 for timeout_ms */ \
|
||||
u32 *tmp = (typeof(timeout_ms) *)NULL; \
|
||||
(void)tmp; \
|
||||
if (timeout_ms > 0U) { \
|
||||
long _ret = wait_event_timeout((c)->wq, condition, \
|
||||
msecs_to_jiffies(timeout_ms)); \
|
||||
if (_ret == 0) \
|
||||
ret = -ETIMEDOUT; \
|
||||
} else { \
|
||||
wait_event((c)->wq, condition); \
|
||||
} \
|
||||
ret;\
|
||||
})
|
||||
|
||||
/**
|
||||
* DCE_COND_WAIT_INTERRUPTIBLE_TIMEOUT - Wait for a condition to be true
|
||||
*
|
||||
* @c - The condition variable to sleep on
|
||||
* @condition - The condition that needs to be true
|
||||
* @timeout_ms - Timeout in milliseconds, or 0 for infinite wait.
|
||||
* This parameter must be a u32. Since this is a macro, this is
|
||||
* enforced by assigning a typecast NULL pointer to a u32 tmp
|
||||
* variable which will generate a compiler warning (or error if
|
||||
* the warning is configured as an error).
|
||||
*
|
||||
* Wait for a condition to become true. Returns -ETIMEOUT if
|
||||
* the wait timed out with condition false or -ERESTARTSYS on
|
||||
* signal.
|
||||
*/
|
||||
#define DCE_COND_WAIT_INTERRUPTIBLE_TIMEOUT(c, condition, timeout_ms) \
|
||||
({ \
|
||||
int ret = 0; \
|
||||
/* This is the assignment to enforce a u32 for timeout_ms */ \
|
||||
u32 *tmp = (typeof(timeout_ms) *)NULL; \
|
||||
(void)tmp; \
|
||||
if (timeout_ms > 0U) { \
|
||||
long _ret = wait_event_interruptible_timeout((c)->wq, \
|
||||
condition, msecs_to_jiffies(timeout_ms)); \
|
||||
if (_ret == 0) \
|
||||
ret = -ETIMEDOUT; \
|
||||
else if (_ret == -ERESTARTSYS) \
|
||||
ret = -ERESTARTSYS; \
|
||||
} else { \
|
||||
ret = wait_event_interruptible((c)->wq, condition); \
|
||||
} \
|
||||
ret; \
|
||||
})
|
||||
|
||||
int dce_cond_init(struct dce_cond *cond);
|
||||
|
||||
void dce_cond_signal(struct dce_cond *cond);
|
||||
|
||||
void dce_cond_signal_interruptible(struct dce_cond *cond);
|
||||
|
||||
int dce_cond_broadcast(struct dce_cond *cond);
|
||||
|
||||
int dce_cond_broadcast_interruptible(struct dce_cond *cond);
|
||||
|
||||
void dce_cond_destroy(struct dce_cond *cond);
|
||||
|
||||
#endif
|
||||
42
drivers/platform/tegra/dce/include/dce-debug-perf.h
Normal file
42
drivers/platform/tegra/dce/include/dce-debug-perf.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 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_DEBUG_PERF_H
|
||||
#define DCE_DEBUG_PERF_H
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
int dbg_dce_perf_stats_stats_fops_open(struct inode *inode,
|
||||
struct file *file);
|
||||
ssize_t dbg_dce_perf_stats_stats_fops_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos);
|
||||
|
||||
int dbg_dce_perf_stats_help_fops_open(struct inode *inode,
|
||||
struct file *file);
|
||||
|
||||
ssize_t dbg_dce_perf_format_fops_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos);
|
||||
int dbg_dce_perf_format_fops_open(struct inode *inode, struct file *file);
|
||||
|
||||
int dbg_dce_perf_events_events_fops_open(struct inode *inode,
|
||||
struct file *file);
|
||||
ssize_t dbg_dce_perf_events_events_fops_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos);
|
||||
int dbg_dce_perf_events_help_fops_open(struct inode *inode,
|
||||
struct file *file);
|
||||
#endif
|
||||
104
drivers/platform/tegra/dce/include/dce-fsm.h
Normal file
104
drivers/platform/tegra/dce/include/dce-fsm.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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_FSM_H
|
||||
#define DCE_FSM_H
|
||||
|
||||
#include <dce-cond.h>
|
||||
#include <dce-lock.h>
|
||||
|
||||
/**
|
||||
* enum dce_fsm_event_id_type - IDs to be used to convey various
|
||||
* events throughout the life cycle of dce.
|
||||
*/
|
||||
enum dce_fsm_event_id_type {
|
||||
EVENT_ID_DCE_INVALID = -1,
|
||||
EVENT_ID_DCE_FSM_START = 0,
|
||||
EVENT_ID_DCE_BOOT_COMPLETE_REQUESTED,
|
||||
EVENT_ID_DCE_BOOT_COMPLETE_RECEIVED,
|
||||
EVENT_ID_DCE_BOOT_CMD_MSG_REQUESTED,
|
||||
EVENT_ID_DCE_BOOT_CMD_MSG_RECEIVED,
|
||||
EVENT_ID_DCE_ADMIN_IPC_MSG_REQUESTED,
|
||||
EVENT_ID_DCE_ADMIN_IPC_MSG_RECEIVED,
|
||||
EVENT_ID_DCE_SC7_ENTER_REQUESTED,
|
||||
EVENT_ID_DCE_SC7_ENTERED_RECEIVED,
|
||||
EVENT_ID_DCE_SC7_EXIT_RECEIVED,
|
||||
EVENT_ID_DCE_LOG_REQUESTED,
|
||||
EVENT_ID_DCE_LOG_READY_RECEIVED,
|
||||
EVENT_ID_DCE_ABORT_RECEIVED,
|
||||
EVENT_ID_DCE_CRASH_LOG_RECEIVED,
|
||||
EVENT_ID_DCE_LOG_OVERFLOW_RECEIVED,
|
||||
EVENT_ID_DCE_FSM_STOP,
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_fsm_state - Different states of dce.
|
||||
*/
|
||||
enum dce_fsm_state {
|
||||
STATE_DCE_INVALID = -1,
|
||||
STATE_DCE_FSM_IDLE = 0,
|
||||
STATE_DCE_BOOT_WAIT,
|
||||
STATE_DCE_BOOTCMD_WFI,
|
||||
STATE_DCE_ADMIN_WFI,
|
||||
STATE_DCE_SC7_ENTER_WFI,
|
||||
STATE_DCE_SC7_ENTERED,
|
||||
STATE_DCE_LOG_READY_WFI,
|
||||
STATE_DCE_ABORT,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dce_fsm_info - contains info used by FSM
|
||||
* @d : Pointer to tegra_dce struct
|
||||
* @initialized : If FSM is initialized
|
||||
* @c_state : Current state of FSM
|
||||
* @lock : Mutex to protect FSM operations
|
||||
* @requested_ipcs : Indicate what IPCs/requests are currently running.
|
||||
* In case we support more than one FSM request at a time.
|
||||
*/
|
||||
struct dce_fsm_info {
|
||||
struct tegra_dce *d;
|
||||
bool initialized;
|
||||
enum dce_fsm_state c_state;
|
||||
struct dce_mutex lock;
|
||||
u32 requested_ipcs;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dce_mailbox_send_cmd_params - contains params for callback function
|
||||
* @cmd : u32 command to be send
|
||||
* @interface : interface id on which command need to be sent
|
||||
*/
|
||||
struct dce_mailbox_send_cmd_params {
|
||||
u32 cmd;
|
||||
u32 interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dce_admin_send_msg_params - contains params for callback function
|
||||
* @msg : Pointer to dce_ipc_msg
|
||||
*/
|
||||
struct dce_admin_send_msg_params {
|
||||
struct dce_ipc_message *msg;
|
||||
};
|
||||
|
||||
int dce_fsm_init(struct tegra_dce *d);
|
||||
void dce_fsm_start(struct tegra_dce *d);
|
||||
void dce_fsm_stop(struct tegra_dce *d);
|
||||
void dce_fsm_deinit(struct tegra_dce *d);
|
||||
int dce_fsm_post_event(struct tegra_dce *d,
|
||||
enum dce_fsm_event_id_type event,
|
||||
void *data);
|
||||
|
||||
int dce_handle_fsm_start_event(struct tegra_dce *d, void *params);
|
||||
int dce_handle_event_stub(struct tegra_dce *d, void *params);
|
||||
#endif
|
||||
42
drivers/platform/tegra/dce/include/dce-hsp.h
Normal file
42
drivers/platform/tegra/dce/include/dce-hsp.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020, NVIDIA CORPORATION. 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_HSP_H
|
||||
#define DCE_HSP_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct tegra_dce;
|
||||
|
||||
/**
|
||||
* DCE HSP Shared Semaphore Utility functions. Description
|
||||
* can be found with function definitions.
|
||||
*/
|
||||
u32 dce_ss_get_state(struct tegra_dce *d, u8 id);
|
||||
void dce_ss_set(struct tegra_dce *d, u8 bpos, u8 id);
|
||||
void dce_ss_clear(struct tegra_dce *d, u8 bpos, u8 id);
|
||||
|
||||
/**
|
||||
* DCE HSP Shared Mailbox Utility functions. Description
|
||||
* can be found with function definitions.
|
||||
*/
|
||||
void dce_smb_set(struct tegra_dce *d, u32 val, u8 id);
|
||||
void dce_smb_set_full_ie(struct tegra_dce *d, bool en, u8 id);
|
||||
u32 dce_smb_read_full_ie(struct tegra_dce *d, u8 id);
|
||||
void dce_smb_set_empty_ie(struct tegra_dce *d, bool en, u8 id);
|
||||
u32 dce_smb_read(struct tegra_dce *d, u8 id);
|
||||
u32 dce_hsp_ie_read(struct tegra_dce *d, u8 id);
|
||||
void dce_hsp_ie_write(struct tegra_dce *d, u32 val, u8 id);
|
||||
u32 dce_hsp_ir_read(struct tegra_dce *d);
|
||||
|
||||
#endif
|
||||
198
drivers/platform/tegra/dce/include/dce-ipc.h
Normal file
198
drivers/platform/tegra/dce/include/dce-ipc.h
Normal file
@@ -0,0 +1,198 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2019-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_IPC_H
|
||||
#define DCE_IPC_H
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <dce-lock.h>
|
||||
#include <soc/tegra/ivc.h>
|
||||
#include <interface/dce-admin-cmds.h>
|
||||
#include <interface/dce-core-interface-ipc-types.h>
|
||||
#include <interface/dce-ipc-state.h>
|
||||
#include <linux/platform/tegra/dce/dce-client-ipc.h>
|
||||
|
||||
#define DCE_IPC_CHANNEL_TYPE_ADMIN 0U
|
||||
#define DCE_IPC_CHANNEL_TYPE_CPU_CLIENTS 1U
|
||||
|
||||
#define DCE_IPC_MAX_IVC_CHANNELS 4U
|
||||
|
||||
/**
|
||||
* TODO : Move the DispRM max to a config file
|
||||
*/
|
||||
#define DCE_DISPRM_CMD_MAX_NFRAMES 1U
|
||||
#define DCE_DISPRM_CMD_MAX_FSIZE 4096U
|
||||
#define DCE_DISPRM_EVENT_NOTIFY_CMD_MAX_NFRAMES 4U
|
||||
#define DCE_DISPRM_EVENT_NOTIFY_CMD_MAX_FSIZE 4096U
|
||||
#define DCE_ADMIN_CMD_MAX_FSIZE 2048U
|
||||
|
||||
#define DCE_IPC_WAIT_TYPE_INVALID 0U
|
||||
#define DCE_IPC_WAIT_TYPE_RPC 1U
|
||||
|
||||
#define DCE_IPC_CHANNEL_VALID BIT(0)
|
||||
#define DCE_IPC_CHANNEL_INITIALIZED BIT(1)
|
||||
#define DCE_IPC_CHANNEL_SYNCED BIT(2)
|
||||
#define DCE_IPC_CHANNEL_MSG_HEADER BIT(15)
|
||||
|
||||
#define DCE_IPC_CH_KMD_TYPE_ADMIN 0U
|
||||
#define DCE_IPC_CH_KMD_TYPE_RM 1U
|
||||
#define DCE_IPC_CH_KMD_TYPE_HDCP 2U
|
||||
#define DCE_IPC_CH_KMD_TYPE_RM_NOTIFY 3U
|
||||
#define DCE_IPC_CH_KMD_TYPE_MAX 4U
|
||||
/**
|
||||
* struct dce_ipc_signal - Stores ivc channel details
|
||||
*
|
||||
* @d : Pointer to struct tegra_dce.
|
||||
* @ibuff : Pointer to the input data buffer.
|
||||
* @obuff : Pointer to the output data buffer.
|
||||
* @d_ivc : Pointer to the ivc data structure.
|
||||
*/
|
||||
struct dce_ipc_mailbox {
|
||||
u8 mb_type;
|
||||
u32 mb_num;
|
||||
};
|
||||
|
||||
/**
|
||||
* TODO : Use linux doorbell driver
|
||||
*/
|
||||
struct dce_ipc_doorbell {
|
||||
u32 db_num;
|
||||
u32 db_bit;
|
||||
};
|
||||
|
||||
struct dce_ipc_signal_instance {
|
||||
u32 type;
|
||||
u32 sema_num;
|
||||
u32 sema_bit;
|
||||
union {
|
||||
struct dce_ipc_mailbox mbox;
|
||||
struct dce_ipc_doorbell db;
|
||||
} form;
|
||||
struct dce_ipc_signal *signal;
|
||||
struct dce_ipc_signal_instance *next;
|
||||
};
|
||||
|
||||
typedef void (*dce_ipc_signal_notify)(struct tegra_dce *d,
|
||||
struct dce_ipc_signal_instance *signal);
|
||||
|
||||
struct dce_ipc_signal {
|
||||
struct dce_ipc_channel *ch;
|
||||
dce_ipc_signal_notify notify;
|
||||
struct dce_ipc_signal_instance to_d;
|
||||
struct dce_ipc_signal_instance from_d;
|
||||
};
|
||||
|
||||
int dce_ipc_signal_init(struct dce_ipc_channel *chan);
|
||||
|
||||
|
||||
/**
|
||||
* struct dce_ipc_region - Contains ivc region specific memory info.
|
||||
*
|
||||
* @size : total IVC region size.
|
||||
* @tx : transmit region info.
|
||||
* @rx : receive region info.
|
||||
*/
|
||||
struct dce_ipc_region {
|
||||
u32 s_offset;
|
||||
dma_addr_t iova;
|
||||
unsigned long size;
|
||||
void *base;
|
||||
};
|
||||
|
||||
struct dce_ipc_queue_info {
|
||||
u8 nframes;
|
||||
u32 frame_sz;
|
||||
dma_addr_t rx_iova;
|
||||
dma_addr_t tx_iova;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dce_ipc_channel - Stores ivc channel details
|
||||
*
|
||||
* @d : Pointer to struct tegra_dce.
|
||||
* @ibuff : Pointer to the input data buffer.
|
||||
* @obuff : Pointer to the output data buffer.
|
||||
* @d_ivc : Pointer to the ivc data structure.
|
||||
*/
|
||||
struct dce_ipc_channel {
|
||||
u32 flags;
|
||||
u32 w_type;
|
||||
u32 ch_type;
|
||||
u32 ipc_type;
|
||||
#if (KERNEL_VERSION(6, 2, 0) <= LINUX_VERSION_CODE)
|
||||
struct iosys_map ibuff;
|
||||
struct iosys_map obuff;
|
||||
#else
|
||||
void *ibuff;
|
||||
void *obuff;
|
||||
#endif
|
||||
struct tegra_ivc d_ivc;
|
||||
struct tegra_dce *d;
|
||||
struct dce_mutex lock;
|
||||
struct dce_ipc_signal signal;
|
||||
struct dce_ipc_queue_info q_info;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dce_ipc - Stores ipc data
|
||||
*
|
||||
* @region - Store data about ivc region in DRAM
|
||||
* @ch - Array of pointers to store dce ivc channel info
|
||||
*/
|
||||
struct dce_ipc {
|
||||
struct dce_ipc_region region;
|
||||
struct dce_ipc_channel *ch[DCE_IPC_MAX_IVC_CHANNELS];
|
||||
};
|
||||
|
||||
int dce_ipc_send_message(struct tegra_dce *d,
|
||||
u32 ch_type, const void *data, size_t size);
|
||||
|
||||
int dce_ipc_read_message(struct tegra_dce *d,
|
||||
u32 ch_type, void *data, size_t size);
|
||||
|
||||
int dce_ipc_send_message_sync(struct tegra_dce *d,
|
||||
u32 ch_type, struct dce_ipc_message *msg);
|
||||
|
||||
int dce_ipc_get_channel_info(struct tegra_dce *d,
|
||||
struct dce_ipc_queue_info *q_info, u32 ch_index);
|
||||
|
||||
void dce_ipc_free_region(struct tegra_dce *d);
|
||||
|
||||
int dce_ipc_allocate_region(struct tegra_dce *d);
|
||||
|
||||
struct tegra_dce *dce_ipc_get_dce_from_ch(u32 ch_type);
|
||||
|
||||
int dce_ipc_channel_init(struct tegra_dce *d, u32 ch_type);
|
||||
|
||||
void dce_ipc_channel_deinit(struct tegra_dce *d, u32 ch_type);
|
||||
|
||||
void dce_ipc_channel_reset(struct tegra_dce *d, u32 ch_type);
|
||||
|
||||
uint32_t dce_ipc_get_ipc_type(struct tegra_dce *d, u32 ch_type);
|
||||
|
||||
bool dce_ipc_channel_is_ready(struct tegra_dce *d, u32 ch_type);
|
||||
|
||||
bool dce_ipc_channel_is_synced(struct tegra_dce *d, u32 ch_type);
|
||||
|
||||
u32 dce_ipc_get_cur_wait_type(struct tegra_dce *d, u32 ch_type);
|
||||
|
||||
bool dce_ipc_is_data_available(struct tegra_dce *d, u32 ch_type);
|
||||
|
||||
int dce_ipc_get_region_iova_info(struct tegra_dce *d, u64 *iova, u32 *size);
|
||||
|
||||
int dce_ipc_init_signaling(struct tegra_dce *d, struct dce_ipc_channel *ch);
|
||||
|
||||
void dce_ipc_deinit_signaling(struct tegra_dce *d, struct dce_ipc_channel *ch);
|
||||
|
||||
#endif
|
||||
70
drivers/platform/tegra/dce/include/dce-lock.h
Normal file
70
drivers/platform/tegra/dce/include/dce-lock.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020, NVIDIA CORPORATION. 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_LOCK_H
|
||||
#define DCE_LOCK_H
|
||||
|
||||
struct dce_mutex {
|
||||
struct mutex mutex;
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_mutex_init - Initialize dce_mutex in Linux style
|
||||
*
|
||||
* mutex : pointer to the mutext to be initialized.
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
static inline int dce_mutex_init(struct dce_mutex *mutex)
|
||||
{
|
||||
mutex_init(&mutex->mutex);
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_mutex_lock - Acquire the dce_mutex in Linux style
|
||||
*
|
||||
* mutex : pointer to the mutext to be acquired.
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
static inline void dce_mutex_lock(struct dce_mutex *mutex)
|
||||
{
|
||||
mutex_lock(&mutex->mutex);
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_mutex_unlock - Release the dce_mutex in Linux style
|
||||
*
|
||||
* mutex : pointer to the mutext to be released.
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
static inline void dce_mutex_unlock(struct dce_mutex *mutex)
|
||||
{
|
||||
mutex_unlock(&mutex->mutex);
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_mutex_destroy - Destroy the dce_mutex in Linux style
|
||||
*
|
||||
* mutex : pointer to the mutext to be destroyed.
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
static inline void dce_mutex_destroy(struct dce_mutex *mutex)
|
||||
{
|
||||
mutex_destroy(&mutex->mutex);
|
||||
};
|
||||
|
||||
#endif
|
||||
82
drivers/platform/tegra/dce/include/dce-log.h
Normal file
82
drivers/platform/tegra/dce/include/dce-log.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2022, NVIDIA CORPORATION. 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_LOG_H
|
||||
#define DCE_LOG_H
|
||||
|
||||
struct tegra_dce;
|
||||
|
||||
enum dce_log_type {
|
||||
DCE_ERROR,
|
||||
DCE_WARNING,
|
||||
DCE_INFO,
|
||||
DCE_DEBUG,
|
||||
};
|
||||
|
||||
/*
|
||||
* Each OS must implement these functions. They handle the OS specific nuances
|
||||
* of printing data to a UART, log, whatever.
|
||||
*/
|
||||
__printf(5, 6)
|
||||
void dce_log_msg(struct tegra_dce *d, const char *func_name, int line,
|
||||
enum dce_log_type type, const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* dce_err - Print an error
|
||||
*
|
||||
* @d - Pointer to tegra_dce.
|
||||
* @fmt - A format string (printf style).
|
||||
* @arg... - Arguments for the format string.
|
||||
*
|
||||
* Uncondtionally print an error message.
|
||||
*/
|
||||
#define dce_err(d, fmt, arg...) \
|
||||
dce_log_msg(d, __func__, __LINE__, DCE_ERROR, fmt, ##arg)
|
||||
|
||||
/**
|
||||
* dce_warn - Print a warning
|
||||
*
|
||||
* @d - Pointer to tegra_dce.
|
||||
* @fmt - A format string (printf style).
|
||||
* @arg... - Arguments for the format string.
|
||||
*
|
||||
* Uncondtionally print a warming message.
|
||||
*/
|
||||
#define dce_warn(d, fmt, arg...) \
|
||||
dce_log_msg(d, __func__, __LINE__, DCE_WARNING, fmt, ##arg)
|
||||
|
||||
/**
|
||||
* dce_info - Print an info message
|
||||
*
|
||||
* @d - Pointer to tegra_dce.
|
||||
* @fmt - A format string (printf style).
|
||||
* @arg... - Arguments for the format string.
|
||||
*
|
||||
* Unconditionally print an information message.
|
||||
*/
|
||||
#define dce_info(d, fmt, arg...) \
|
||||
dce_log_msg(d, __func__, __LINE__, DCE_INFO, fmt, ##arg)
|
||||
|
||||
/**
|
||||
* dce_debug - Print a debug message
|
||||
*
|
||||
* @d - Pointer to tegra_dce.
|
||||
* @fmt - A format string (printf style).
|
||||
* @arg... - Arguments for the format string.
|
||||
*
|
||||
* print a debug message.
|
||||
*/
|
||||
#define dce_debug(d, fmt, arg...) \
|
||||
dce_log_msg(d, __func__, __LINE__, DCE_DEBUG, fmt, ##arg)
|
||||
|
||||
#endif
|
||||
68
drivers/platform/tegra/dce/include/dce-mailbox.h
Normal file
68
drivers/platform/tegra/dce/include/dce-mailbox.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2022, NVIDIA CORPORATION. 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_MAILBOX_H
|
||||
#define DCE_MAILBOX_H
|
||||
|
||||
struct tegra_dce;
|
||||
|
||||
#define DCE_MAILBOX_BOOT_INTERFACE 0U
|
||||
#define DCE_MAILBOX_ADMIN_INTERFACE 1U
|
||||
#define DCE_MAILBOX_DISPRM_INTERFACE 2U
|
||||
#define DCE_MAILBOX_DISPRM_NOTIFY_INTERFACE 3U
|
||||
#define DCE_MAILBOX_MAX_INTERFACES 4U
|
||||
|
||||
/**
|
||||
* struct dce_mailbox_interface - Contains dce mailbox interface state info
|
||||
*
|
||||
* @lock : dce_mutext for this mailbox interface.
|
||||
* @state : Stores the current status of the mailbox interface.
|
||||
* @ack_value : Stores the response received from dce f/w on an interface.
|
||||
* @s_mb : mailbox used to send commands to DCE CCPLEX for this interface.
|
||||
* @r_mb : mailbox used to receive commands from DCE for this interface.
|
||||
* @valid : true if the stored status is valid.
|
||||
*/
|
||||
struct dce_mailbox_interface {
|
||||
u8 s_mb;
|
||||
u8 r_mb;
|
||||
int state;
|
||||
bool valid;
|
||||
void *notify_data;
|
||||
struct dce_mutex lock;
|
||||
unsigned int ack_value;
|
||||
int (*dce_mailbox_wait)(struct tegra_dce *);
|
||||
void (*notify)(struct tegra_dce *, void *);
|
||||
};
|
||||
|
||||
|
||||
u32 dce_mailbox_get_interface_status(struct tegra_dce *d, u8 id);
|
||||
|
||||
void dce_mailbox_store_interface_status(struct tegra_dce *d,
|
||||
u32 v, u8 id);
|
||||
|
||||
void dce_mailbox_invalidate_status(struct tegra_dce *d, u8 id);
|
||||
|
||||
void dce_mailbox_isr(struct tegra_dce *d);
|
||||
|
||||
void dce_mailbox_set_full_interrupt(struct tegra_dce *d, u8 id);
|
||||
|
||||
int dce_mailbox_send_cmd_sync(struct tegra_dce *d, u32 cmd, u32 interface);
|
||||
int dce_handle_mailbox_send_cmd_sync(struct tegra_dce *d, u32 cmd, u32 interface);
|
||||
|
||||
int dce_mailbox_init_interface(struct tegra_dce *d, u8 id, u8 s_mb,
|
||||
u8 r_mb, int (*dce_mailbox_wait)(struct tegra_dce *),
|
||||
void *notify_data, void (*notify)(struct tegra_dce *, void *));
|
||||
|
||||
void dce_mailbox_deinit_interface(struct tegra_dce *d, u8 id);
|
||||
|
||||
#endif
|
||||
30
drivers/platform/tegra/dce/include/dce-pm.h
Normal file
30
drivers/platform/tegra/dce/include/dce-pm.h
Normal 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
|
||||
25
drivers/platform/tegra/dce/include/dce-regs.h
Normal file
25
drivers/platform/tegra/dce/include/dce-regs.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020, NVIDIA CORPORATION. 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_REGS_H
|
||||
#define DCE_REGS_H
|
||||
|
||||
|
||||
#include <hw/hw_evp_dce.h>
|
||||
#include <hw/hw_ast_dce.h>
|
||||
#include <hw/hw_hsp_dce.h>
|
||||
#include <hw/hw_pm_dce.h>
|
||||
|
||||
#define DCE_MAX_HSP 2
|
||||
|
||||
#endif /* DCE_REGS_H */
|
||||
42
drivers/platform/tegra/dce/include/dce-thread.h
Normal file
42
drivers/platform/tegra/dce/include/dce-thread.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020, NVIDIA CORPORATION. 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_THREAD_H
|
||||
#define DCE_THREAD_H
|
||||
|
||||
#include <linux/sched.h>
|
||||
|
||||
struct task_struct;
|
||||
|
||||
struct dce_thread {
|
||||
struct task_struct *task;
|
||||
bool running;
|
||||
int (*fn)(void *);
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct dce_thread;
|
||||
|
||||
int dce_thread_create(struct dce_thread *thread,
|
||||
void *data,
|
||||
int (*threadfn)(void *data), const char *name);
|
||||
|
||||
void dce_thread_stop(struct dce_thread *thread);
|
||||
|
||||
bool dce_thread_should_stop(struct dce_thread *thread);
|
||||
|
||||
bool dce_thread_is_running(struct dce_thread *thread);
|
||||
|
||||
void dce_thread_join(struct dce_thread *thread);
|
||||
|
||||
#endif
|
||||
64
drivers/platform/tegra/dce/include/dce-util-common.h
Normal file
64
drivers/platform/tegra/dce/include/dce-util-common.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2022, NVIDIA CORPORATION. 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_UTIL_COMMON_H
|
||||
#define DCE_UTIL_COMMON_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
/**
|
||||
* This file contains all dce common fucntions and data strutcures which are
|
||||
* abstarcted out from the operating system. The underlying OS layer will
|
||||
* implement the pertinent low level details. This design is to make sure that
|
||||
* dce cpu driver can be leveraged across multiple OSes if the neede arises.
|
||||
*/
|
||||
|
||||
struct tegra_dce;
|
||||
|
||||
void dce_writel(struct tegra_dce *d, u32 r, u32 v);
|
||||
|
||||
u32 dce_readl(struct tegra_dce *d, u32 r);
|
||||
|
||||
void dce_writel_check(struct tegra_dce *d, u32 r, u32 v);
|
||||
|
||||
bool dce_io_exists(struct tegra_dce *d);
|
||||
|
||||
bool dce_io_valid_reg(struct tegra_dce *d, u32 r);
|
||||
|
||||
struct dce_firmware *dce_request_firmware(struct tegra_dce *d,
|
||||
const char *fw_name);
|
||||
|
||||
void dce_release_fw(struct tegra_dce *d, struct dce_firmware *fw);
|
||||
|
||||
void *dce_kzalloc(struct tegra_dce *d, size_t size, bool dma_flag);
|
||||
|
||||
void dce_kfree(struct tegra_dce *d, void *addr);
|
||||
|
||||
unsigned long dce_get_nxt_pow_of_2(unsigned long *addr, u8 nbits);
|
||||
|
||||
static inline void dce_bitmap_set(unsigned long *map,
|
||||
unsigned int start, unsigned int len)
|
||||
{
|
||||
bitmap_set(map, start, (int)len);
|
||||
}
|
||||
|
||||
static inline void dce_bitmap_clear(unsigned long *map,
|
||||
unsigned int start, unsigned int len)
|
||||
{
|
||||
bitmap_clear(map, start, (int)len);
|
||||
}
|
||||
|
||||
#endif
|
||||
41
drivers/platform/tegra/dce/include/dce-worker.h
Normal file
41
drivers/platform/tegra/dce/include/dce-worker.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2022, 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_WORKER_H
|
||||
#define DCE_WORKER_H
|
||||
|
||||
#include <dce-cond.h>
|
||||
#include <dce-lock.h>
|
||||
#include <dce-thread.h>
|
||||
|
||||
struct tegra_dce;
|
||||
|
||||
#define DCE_WAIT_BOOT_COMPLETE 0
|
||||
#define DCE_WAIT_BOOT_CMD 1
|
||||
#define DCE_WAIT_ADMIN_IPC 2
|
||||
#define DCE_WAIT_SC7_ENTER 3
|
||||
#define DCE_WAIT_LOG 4
|
||||
#define DCE_MAX_WAIT 5
|
||||
|
||||
struct dce_wait_cond {
|
||||
atomic_t complete;
|
||||
struct dce_cond cond_wait;
|
||||
};
|
||||
|
||||
int dce_work_cond_sw_resource_init(struct tegra_dce *d);
|
||||
void dce_work_cond_sw_resource_deinit(struct tegra_dce *d);
|
||||
void dce_schedule_boot_complete_wait_worker(struct tegra_dce *d);
|
||||
int dce_wait_interruptible(struct tegra_dce *d, u32 msg_id);
|
||||
void dce_wakeup_interruptible(struct tegra_dce *d, u32 msg_id);
|
||||
|
||||
#endif
|
||||
30
drivers/platform/tegra/dce/include/dce-workqueue.h
Normal file
30
drivers/platform/tegra/dce/include/dce-workqueue.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2022, NVIDIA CORPORATION. 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_WORKQUEUE_H
|
||||
#define DCE_WORKQUEUE_H
|
||||
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
struct dce_work_struct {
|
||||
struct tegra_dce *d;
|
||||
struct work_struct work;
|
||||
void (*dce_work_fn)(struct tegra_dce *d);
|
||||
};
|
||||
|
||||
int dce_init_work(struct tegra_dce *d,
|
||||
struct dce_work_struct *work,
|
||||
void (*work_fn)(struct tegra_dce *d));
|
||||
void dce_schedule_work(struct dce_work_struct *work);
|
||||
|
||||
#endif
|
||||
460
drivers/platform/tegra/dce/include/dce.h
Normal file
460
drivers/platform/tegra/dce/include/dce.h
Normal file
@@ -0,0 +1,460 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2019-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 TEGRA_DCE_H
|
||||
#define TEGRA_DCE_H
|
||||
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/types.h>
|
||||
#include <dce-log.h>
|
||||
#include <dce-ipc.h>
|
||||
#include <dce-hsp.h>
|
||||
#include <dce-lock.h>
|
||||
#include <dce-cond.h>
|
||||
#include <dce-regs.h>
|
||||
#include <dce-thread.h>
|
||||
#include <dce-worker.h>
|
||||
#include <dce-fsm.h>
|
||||
#include <dce-pm.h>
|
||||
#include <dce-mailbox.h>
|
||||
#include <dce-client-ipc-internal.h>
|
||||
#include <dce-workqueue.h>
|
||||
|
||||
#define DCE_MAX_CPU_IRQS 4
|
||||
|
||||
/**
|
||||
* DCE Boot Status : DCE Driver Init States
|
||||
*
|
||||
* @DCE_EARLY_INIT_* : Driver Init Before Bootstrap
|
||||
* @DCE_AST_CONFIG_* : Used When DCE-CPU Driver Loads the Firmware
|
||||
*/
|
||||
#define DCE_EARLY_INIT_START DCE_BIT(31)
|
||||
#define DCE_EARLY_INIT_FAILED DCE_BIT(30)
|
||||
#define DCE_EARLY_INIT_DONE DCE_BIT(29)
|
||||
#define DCE_AST_CONFIG_START DCE_BIT(28)
|
||||
#define DCE_AST_CONFIG_FAILED DCE_BIT(27)
|
||||
#define DCE_AST_CONFIG_DONE DCE_BIT(26)
|
||||
/**
|
||||
* DCE Boot Status: FW Boot States
|
||||
*/
|
||||
#define DCE_FW_EARLY_BOOT_START DCE_BIT(16)
|
||||
#define DCE_FW_EARLY_BOOT_FAILED DCE_BIT(15)
|
||||
#define DCE_FW_EARLY_BOOT_DONE DCE_BIT(14)
|
||||
#define DCE_FW_BOOTSTRAP_START DCE_BIT(13)
|
||||
#define DCE_FW_BOOTSTRAP_FAILED DCE_BIT(12)
|
||||
#define DCE_FW_BOOTSTRAP_DONE DCE_BIT(11)
|
||||
#define DCE_FW_ADMIN_SEQ_START DCE_BIT(10)
|
||||
#define DCE_FW_ADMIN_SEQ_FAILED DCE_BIT(9)
|
||||
#define DCE_FW_ADMIN_SEQ_DONE DCE_BIT(8)
|
||||
#define DCE_FW_SUSPENDED DCE_BIT(2)
|
||||
#define DCE_FW_BOOT_DONE DCE_BIT(1)
|
||||
#define DCE_STATUS_FAILED DCE_BIT(0)
|
||||
#define DCE_STATUS_UNKNOWN ((u32)(0))
|
||||
|
||||
struct tegra_dce;
|
||||
|
||||
/**
|
||||
* struct dce_platform_data - Data Structure to hold platform specific DCE
|
||||
* cluster data.
|
||||
*/
|
||||
struct dce_platform_data {
|
||||
/**
|
||||
* @fw_dce_addr : Stores the firmware address that DCE sees before being
|
||||
* converted by AST.
|
||||
*/
|
||||
u32 fw_dce_addr;
|
||||
/**
|
||||
* fw_image_size : Stores the max size of DCE fw.
|
||||
*/
|
||||
u32 fw_img_size;
|
||||
/**
|
||||
* @fw_info_valid : Tells if the above address and size info are valid.
|
||||
* CPU driver will use this info just for debug purpose.
|
||||
*/
|
||||
bool fw_info_valid;
|
||||
/**
|
||||
* @no_of_asts : Stores max no. of ASTs in the DCE Cluster
|
||||
*/
|
||||
u8 no_of_asts;
|
||||
/**
|
||||
* phys_stream_id : Physical stream ID to be programmed for debug
|
||||
* purpose only.
|
||||
*/
|
||||
u32 phys_stream_id;
|
||||
/**
|
||||
* stream_id : Stream ID to program the ASTs in debug mode
|
||||
* only.
|
||||
*/
|
||||
u8 stream_id;
|
||||
/**
|
||||
* hsp_id - HSP instance id used for dce communication
|
||||
*/
|
||||
u32 hsp_id;
|
||||
/**
|
||||
* fw_vmindex : VMIndex to program the AST region to read FW in debug
|
||||
* mode only.
|
||||
*/
|
||||
u8 fw_vmindex;
|
||||
/**
|
||||
* fw_carveout_id : Carveout ID to program the AST region to read FW in
|
||||
* debug mode only.
|
||||
*/
|
||||
u8 fw_carveout_id;
|
||||
/**
|
||||
* @fw_name : Stores dce fw name
|
||||
*/
|
||||
const char *fw_name;
|
||||
/**
|
||||
* @use_physical_id : Use physical streamid
|
||||
*/
|
||||
bool use_physical_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dce_firmware - Contains dce firmware info
|
||||
*
|
||||
* @data : u8 pointer to hold the fw data
|
||||
* @size : size of the fw
|
||||
* @dma_handle : stores the dma_handle for firmware
|
||||
*/
|
||||
struct dce_firmware {
|
||||
u8 *data;
|
||||
size_t size;
|
||||
u64 dma_handle;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tegra_dce - Primary OS independent tegra dce structure to hold dce
|
||||
* cluster's and it's element's runtime info.
|
||||
*/
|
||||
struct tegra_dce {
|
||||
/**
|
||||
* @irq - Array of irqs to be handled by cpu from dce cluster.
|
||||
*/
|
||||
u32 irq[DCE_MAX_CPU_IRQS];
|
||||
/**
|
||||
* @fsm_info - Data Structure to manage dce FSM states.
|
||||
*/
|
||||
struct dce_fsm_info fsm_info;
|
||||
/**
|
||||
* dce_bootstrap_work : dce work to be executed to start FSM flow
|
||||
*/
|
||||
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
|
||||
*/
|
||||
struct dce_wait_cond ipc_waits[DCE_MAX_WAIT];
|
||||
/**
|
||||
* dce_bootstrap_done - Data structure to manage wait for boot done
|
||||
*/
|
||||
struct dce_cond dce_bootstrap_done;
|
||||
/**
|
||||
* @d_mb - Stores the current status of dce mailbox interfaces.
|
||||
*/
|
||||
struct dce_mailbox_interface d_mb[DCE_MAILBOX_MAX_INTERFACES];
|
||||
/**
|
||||
* @d_ipc - Stores the ipc related data between CPU and DCE.
|
||||
*/
|
||||
struct dce_ipc d_ipc;
|
||||
/**
|
||||
* @d_clients - Stores all dce clients data.
|
||||
*/
|
||||
struct tegra_dce_client_ipc *d_clients[DCE_CLIENT_IPC_TYPE_MAX];
|
||||
|
||||
/**
|
||||
* @d_async_ipc_info - stores data to handle async events
|
||||
*/
|
||||
struct tegra_dce_async_ipc_info d_async_ipc;
|
||||
/**
|
||||
* @hsp_id - HSP instance id used for dce communication
|
||||
*/
|
||||
u32 hsp_id;
|
||||
/**
|
||||
* @boot_status - u32 variable to store dce's boot status.
|
||||
*/
|
||||
u32 boot_status;
|
||||
/**
|
||||
* @boot_complete - Boolean variable to store dce's boot status.
|
||||
*/
|
||||
bool boot_complete;
|
||||
/**
|
||||
* @ast_config_complete - Boolean variable to store dce's ast
|
||||
* configuration status.
|
||||
*/
|
||||
bool ast_config_complete;
|
||||
/**
|
||||
* @reset_complete - Boolean variable to store dce's reset status.
|
||||
*/
|
||||
bool reset_complete;
|
||||
/**
|
||||
* @load_complete - Boolean variable to store dce's fw load status.
|
||||
*/
|
||||
bool load_complete;
|
||||
/**
|
||||
* @log_level - Stores the log level for dce cpu prints.
|
||||
*/
|
||||
u32 log_level;
|
||||
/**
|
||||
* @fw_data - Stores info regardign firmware to be used runtime.
|
||||
*/
|
||||
struct dce_firmware *fw_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dce_device - DCE data structure for storing
|
||||
* linux device specific info.
|
||||
*/
|
||||
struct dce_device {
|
||||
/**
|
||||
* @d : OS agnostic dce struct. Stores all runitme info for dce cluster
|
||||
* elements.
|
||||
*/
|
||||
struct tegra_dce d;
|
||||
/**
|
||||
* @dev : Pointer to DCE Cluster's Linux device struct.
|
||||
*/
|
||||
struct device *dev;
|
||||
/**
|
||||
* @pdata : Pointer to dce platform data struct.
|
||||
*/
|
||||
struct dce_platform_data *pdata;
|
||||
/**
|
||||
* @max_cpu_irqs : stores maximum no. os irqs from DCE cluster to CPU
|
||||
* for this platform.
|
||||
*/
|
||||
u8 max_cpu_irqs;
|
||||
/**
|
||||
* @regs : Stores the cpu-mapped base address of DCE Cluster. Will be
|
||||
* used for MMIO transactions to DCE elements.
|
||||
*/
|
||||
void __iomem *regs;
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
/**
|
||||
* @debugfs : Debugfs node for DCE Linux device.
|
||||
*/
|
||||
struct dentry *debugfs;
|
||||
/**
|
||||
* @ext_test_status : Return code for external client tests run via
|
||||
* debugfs
|
||||
*/
|
||||
s32 ext_test_status;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_device_from_dce - inline function to get linux os data from the
|
||||
* os agnostic struct tegra_dc
|
||||
* @d : Pointer to the os agnostic tegra_dce data structure.
|
||||
*
|
||||
* Return : pointer to struct dce_device
|
||||
*/
|
||||
static inline struct dce_device *dce_device_from_dce(struct tegra_dce *d)
|
||||
{
|
||||
return container_of(d, struct dce_device, d);
|
||||
}
|
||||
|
||||
/**
|
||||
* dev_from_dce - inline function to get linux device from the
|
||||
* os agnostic struct tegra_dc
|
||||
* @d : Pointer to the os agnostic tegra_dce data structure.
|
||||
*
|
||||
* Return : pointer to struct device
|
||||
*/
|
||||
static inline struct device *dev_from_dce(struct tegra_dce *d)
|
||||
{
|
||||
return dce_device_from_dce(d)->dev;
|
||||
}
|
||||
|
||||
/**
|
||||
* pdata_from_dce - inline function to get dce platform data from
|
||||
* the os agnostic struct tegra_dc.
|
||||
*
|
||||
* @d : Pointer to the os agnostic tegra_dce data structure.
|
||||
*
|
||||
* Return : pointer to struct device
|
||||
*/
|
||||
static inline struct dce_platform_data *pdata_from_dce(struct tegra_dce *d)
|
||||
{
|
||||
return ((struct dce_device *)dev_get_drvdata(dev_from_dce(d)))->pdata;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_set_boot_complete - updates the current dce boot complete status.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @val : true or false.
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
static inline void dce_set_boot_complete(struct tegra_dce *d, bool val)
|
||||
{
|
||||
d->boot_complete = val;
|
||||
if (!val)
|
||||
d->boot_status &= (~DCE_FW_BOOT_DONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_is_bootcmds_done - Checks if dce bootstrap bootcmds done.
|
||||
*
|
||||
* Chekc if all the mailbox boot commands are completed
|
||||
*
|
||||
* @d - Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : True if bootcmds are completed
|
||||
*/
|
||||
static inline bool dce_is_bootcmds_done(struct tegra_dce *d)
|
||||
{
|
||||
return (d->boot_status & DCE_FW_BOOTSTRAP_DONE) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_is_bootstrap_done - check if dce bootstrap is done.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : true if bootstrap done else false
|
||||
*/
|
||||
static inline bool dce_is_bootstrap_done(struct tegra_dce *d)
|
||||
{
|
||||
return (d->boot_status & DCE_FW_BOOT_DONE) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_set_ast_config_status - updates the current status of ast configuration.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @val : true or false.
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
static inline void dce_set_ast_config_status(struct tegra_dce *d, bool val)
|
||||
{
|
||||
d->ast_config_complete = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_set_dce_reset_status - updates the current status of dce reset.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @val : true or false.
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
static inline void dce_set_dce_reset_status(struct tegra_dce *d, bool val)
|
||||
{
|
||||
d->reset_complete = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_set_load_fw_status - updates the current status of fw loading.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @val : true or false stating fw load is complete or incomplete respectiveely.
|
||||
*
|
||||
* Return : void
|
||||
*/
|
||||
static inline void dce_set_load_fw_status(struct tegra_dce *d, bool val)
|
||||
{
|
||||
d->load_complete = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Common Utility Functions. Description can be found with
|
||||
* function definitions.
|
||||
*/
|
||||
u8 dce_get_phys_stream_id(struct tegra_dce *d);
|
||||
u8 dce_get_dce_stream_id(struct tegra_dce *d);
|
||||
u8 dce_get_fw_vm_index(struct tegra_dce *d);
|
||||
u8 dce_get_fw_carveout_id(struct tegra_dce *d);
|
||||
bool dce_is_physical_id_valid(struct tegra_dce *d);
|
||||
|
||||
u32 dce_get_fw_dce_addr(struct tegra_dce *d);
|
||||
u64 dce_get_fw_phy_addr(struct tegra_dce *d, struct dce_firmware *fw);
|
||||
const char *dce_get_fw_name(struct tegra_dce *d);
|
||||
|
||||
int dce_driver_init(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);
|
||||
int dce_start_bootstrap_flow(struct tegra_dce *d);
|
||||
int dce_boot_interface_init(struct tegra_dce *d);
|
||||
void dce_boot_interface_deinit(struct tegra_dce *d);
|
||||
int dce_handle_boot_cmd_requested_event(struct tegra_dce *d, void *params);
|
||||
int dce_handle_boot_cmd_received_event(struct tegra_dce *d, void *params);
|
||||
int dce_handle_boot_complete_requested_event(struct tegra_dce *d, void *params);
|
||||
int dce_handle_boot_complete_received_event(struct tegra_dce *d, void *params);
|
||||
|
||||
int dce_admin_init(struct tegra_dce *d);
|
||||
void dce_admin_deinit(struct tegra_dce *d);
|
||||
int dce_start_admin_seq(struct tegra_dce *d);
|
||||
struct dce_ipc_message
|
||||
*dce_admin_allocate_message(struct tegra_dce *d);
|
||||
void dce_admin_free_message(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg);
|
||||
int dce_admin_send_msg(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg);
|
||||
void dce_admin_ivc_channel_reset(struct tegra_dce *d);
|
||||
int dce_admin_get_ipc_channel_info(struct tegra_dce *d,
|
||||
struct dce_ipc_queue_info *q_info);
|
||||
int dce_admin_send_cmd_echo(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg);
|
||||
int dce_admin_send_cmd_ext_test(struct tegra_dce *d,
|
||||
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_received_event(struct tegra_dce *d, void *params);
|
||||
int dce_admin_send_cmd_get_perf_stat(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg);
|
||||
int dce_admin_send_cmd_set_perf_stat(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg,
|
||||
bool start_perf);
|
||||
int dce_admin_send_cmd_stop_perf_stat(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg);
|
||||
int dce_admin_send_cmd_get_perf_events(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg);
|
||||
int dce_admin_send_cmd_clear_perf_events(struct tegra_dce *d,
|
||||
struct dce_ipc_message *msg);
|
||||
int dce_admin_ipc_wait(struct tegra_dce *d, u32 w_type);
|
||||
void dce_admin_ipc_handle_signal(struct tegra_dce *d, u32 ch_type);
|
||||
|
||||
bool dce_fw_boot_complete(struct tegra_dce *d);
|
||||
void dce_request_fw_boot_complete(struct tegra_dce *d);
|
||||
|
||||
/**
|
||||
* Functions to be used in debug mode only.
|
||||
*
|
||||
* TODO : Have sanity checks for these not to be
|
||||
* used in non-debug mode.
|
||||
*/
|
||||
void dce_config_ast(struct tegra_dce *d);
|
||||
int dce_reset_dce(struct tegra_dce *d);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
void dce_init_debug(struct tegra_dce *d);
|
||||
void dce_remove_debug(struct tegra_dce *d);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
517
drivers/platform/tegra/dce/include/hw/hw_ast_dce.h
Normal file
517
drivers/platform/tegra/dce/include/hw/hw_ast_dce.h
Normal file
@@ -0,0 +1,517 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020, NVIDIA CORPORATION. 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
* Function naming determines intended use:
|
||||
*
|
||||
* <x>_r(void) : Returns the offset for register <x>.
|
||||
*
|
||||
* <x>_o(void) : Returns the offset for element <x>.
|
||||
*
|
||||
* <x>_w(void) : Returns the word offset for word (4 byte) element <x>.
|
||||
*
|
||||
* <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits.
|
||||
*
|
||||
* <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted
|
||||
* and masked to place it at field <y> of register <x>. This value
|
||||
* can be |'d with others to produce a full register value for
|
||||
* register <x>.
|
||||
*
|
||||
* <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This
|
||||
* value can be ~'d and then &'d to clear the value of field <y> for
|
||||
* register <x>.
|
||||
*
|
||||
* <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted
|
||||
* to place it at field <y> of register <x>. This value can be |'d
|
||||
* with others to produce a full register value for <x>.
|
||||
*
|
||||
* <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register
|
||||
* <x> value 'r' after being shifted to place its LSB at bit 0.
|
||||
* This value is suitable for direct comparison with other unshifted
|
||||
* values appropriate for use in field <y> of register <x>.
|
||||
*
|
||||
* <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for
|
||||
* field <y> of register <x>. This value is suitable for direct
|
||||
* comparison with unshifted values appropriate for use in field <y>
|
||||
* of register <x>.
|
||||
*/
|
||||
#ifndef HW_AST_DCE_H
|
||||
#define HW_AST_DCE_H
|
||||
|
||||
static inline u32 ast_ast0_control_r(void)
|
||||
{
|
||||
return 0x40000U;
|
||||
}
|
||||
static inline u32 ast_ast0_control_write_mask_v(void)
|
||||
{
|
||||
return 0xffdf83e7U;
|
||||
}
|
||||
static inline u32 ast_ast0_control_apbovron_shift_v(void)
|
||||
{
|
||||
return 0x0000001fU;
|
||||
}
|
||||
static inline u32 ast_ast0_control_nicovron_shift_v(void)
|
||||
{
|
||||
return 0x0000001eU;
|
||||
}
|
||||
static inline u32 ast_ast0_control_physstreamid_shift_v(void)
|
||||
{
|
||||
return 0x00000016U;
|
||||
}
|
||||
static inline u32 ast_ast0_control_carveoutlock_true_f(void)
|
||||
{
|
||||
return 0x100000U;
|
||||
}
|
||||
static inline u32 ast_ast0_control_carveoutlock_false_f(void)
|
||||
{
|
||||
return 0x0U;
|
||||
}
|
||||
static inline u32 ast_ast0_control_carveoutlock_defphysical_shift_v(void)
|
||||
{
|
||||
return 0x00000013U;
|
||||
}
|
||||
static inline u32 ast_ast0_control_carveoutlock_defvmindex_shift_v(void)
|
||||
{
|
||||
return 0x0000000fU;
|
||||
}
|
||||
static inline u32 ast_ast0_control_carveoutlock_defcarveoutid_shift_v(void)
|
||||
{
|
||||
return 0x00000005U;
|
||||
}
|
||||
static inline u32 ast_ast0_control_defsnoop_enable_f(void)
|
||||
{
|
||||
return 0x4U;
|
||||
}
|
||||
static inline u32 ast_ast0_control_defsnoop_disable_f(void)
|
||||
{
|
||||
return 0x0U;
|
||||
}
|
||||
static inline u32 ast_ast0_control_matcherrctl_no_decerr_f(void)
|
||||
{
|
||||
return 0x0U;
|
||||
}
|
||||
static inline u32 ast_ast0_control_matcherrctl_decerr_f(void)
|
||||
{
|
||||
return 0x2U;
|
||||
}
|
||||
static inline u32 ast_ast0_control_lock_true_f(void)
|
||||
{
|
||||
return 0x1U;
|
||||
}
|
||||
static inline u32 ast_ast0_control_lock_false_f(void)
|
||||
{
|
||||
return 0x0U;
|
||||
}
|
||||
static inline u32 ast_ast0_error_status_r(void)
|
||||
{
|
||||
return 0x40004U;
|
||||
}
|
||||
static inline u32 ast_ast0_error_addr_lo_r(void)
|
||||
{
|
||||
return 0x40008U;
|
||||
}
|
||||
static inline u32 ast_ast0_error_addr_hi_r(void)
|
||||
{
|
||||
return 0x4000cU;
|
||||
}
|
||||
static inline u32 ast_ast0_streamid_ctl_0_r(void)
|
||||
{
|
||||
return 0x40020U;
|
||||
}
|
||||
static inline u32 ast_ast0_streamid_ctl_0_write_mask_v(void)
|
||||
{
|
||||
return 0x0000ff01U;
|
||||
}
|
||||
static inline u32 ast_ast0_streamid_ctl_0_streamid_shift_v(void)
|
||||
{
|
||||
return 0x00000008U;
|
||||
}
|
||||
static inline u32 ast_ast0_streamid_ctl_0_enable_enable_f(void)
|
||||
{
|
||||
return 0x1U;
|
||||
}
|
||||
static inline u32 ast_ast0_streamid_ctl_0_enable_disable_f(void)
|
||||
{
|
||||
return 0x0U;
|
||||
}
|
||||
static inline u32 ast_ast0_streamid_ctl_1_r(void)
|
||||
{
|
||||
return 0x40024U;
|
||||
}
|
||||
static inline u32 ast_ast0_streamid_ctl_1_write_mask_v(void)
|
||||
{
|
||||
return 0x0000ff01U;
|
||||
}
|
||||
static inline u32 ast_ast0_streamid_ctl_1_streamid_shift_v(void)
|
||||
{
|
||||
return 0x00000008U;
|
||||
}
|
||||
static inline u32 ast_ast0_streamid_ctl_1_enable_enable_f(void)
|
||||
{
|
||||
return 0x1U;
|
||||
}
|
||||
static inline u32 ast_ast0_streamid_ctl_1_enable_disable_f(void)
|
||||
{
|
||||
return 0x0U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_0_slave_base_lo_r(void)
|
||||
{
|
||||
return 0x40100U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_0_slave_base_lo_slvbase_shift_v(void)
|
||||
{
|
||||
return 0x0000000cU;
|
||||
}
|
||||
static inline u32 ast_ast0_region_0_slave_base_lo_write_mask_v(void)
|
||||
{
|
||||
return 0xfffff001U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_0_slave_base_lo_enable_true_f(void)
|
||||
{
|
||||
return 0x1U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_0_slave_base_lo_enable_false_f(void)
|
||||
{
|
||||
return 0x0U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_0_slave_base_hi_r(void)
|
||||
{
|
||||
return 0x40104U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_0_mask_lo_r(void)
|
||||
{
|
||||
return 0x40108U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_0_mask_lo_write_mask_v(void)
|
||||
{
|
||||
return 0xfffff000U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_0_mask_hi_r(void)
|
||||
{
|
||||
return 0x4010cU;
|
||||
}
|
||||
static inline u32 ast_ast0_region_0_mask_hi_write_mask_v(void)
|
||||
{
|
||||
return 0xffffffffU;
|
||||
}
|
||||
static inline u32 ast_ast0_region_0_master_base_lo_r(void)
|
||||
{
|
||||
return 0x40110U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_0_master_base_lo_write_mask_v(void)
|
||||
{
|
||||
return 0xfffff000U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_0_master_base_hi_r(void)
|
||||
{
|
||||
return 0x40114U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_0_control_r(void)
|
||||
{
|
||||
return 0x40118U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_0_control_write_mask_v(void)
|
||||
{
|
||||
return 0x000f83e5U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_0_control_physical_shift_v(void)
|
||||
{
|
||||
return 0x00000013U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_0_control_vmindex_shift_v(void)
|
||||
{
|
||||
return 0x0000000fU;
|
||||
}
|
||||
static inline u32 ast_ast0_region_0_control_carveoutid_shift_v(void)
|
||||
{
|
||||
return 0x00000005U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_0_control_snoop_enable_f(void)
|
||||
{
|
||||
return 0x4U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_0_control_snoop_disable_f(void)
|
||||
{
|
||||
return 0x0U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_0_control_lock_true_f(void)
|
||||
{
|
||||
return 0x1U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_0_control_lock_false_f(void)
|
||||
{
|
||||
return 0x0U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_1_slave_base_lo_r(void)
|
||||
{
|
||||
return 0x40120U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_1_slave_base_hi_r(void)
|
||||
{
|
||||
return 0x40124U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_1_mask_lo_r(void)
|
||||
{
|
||||
return 0x40128U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_1_mask_hi_r(void)
|
||||
{
|
||||
return 0x4012cU;
|
||||
}
|
||||
static inline u32 ast_ast0_region_1_master_base_lo_r(void)
|
||||
{
|
||||
return 0x40130U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_1_master_base_hi_r(void)
|
||||
{
|
||||
return 0x40134U;
|
||||
}
|
||||
static inline u32 ast_ast0_region_1_control_r(void)
|
||||
{
|
||||
return 0x40138U;
|
||||
}
|
||||
static inline u32 ast_ast1_control_r(void)
|
||||
{
|
||||
return 0x50000U;
|
||||
}
|
||||
static inline u32 ast_ast1_control_write_mask_v(void)
|
||||
{
|
||||
return 0xffdf83e7U;
|
||||
}
|
||||
static inline u32 ast_ast1_control_apbovron_shift_v(void)
|
||||
{
|
||||
return 0x0000001fU;
|
||||
}
|
||||
static inline u32 ast_ast1_control_nicovron_shift_v(void)
|
||||
{
|
||||
return 0x0000001eU;
|
||||
}
|
||||
static inline u32 ast_ast1_control_physstreamid_shift_v(void)
|
||||
{
|
||||
return 0x00000016U;
|
||||
}
|
||||
static inline u32 ast_ast1_control_carveoutlock_true_f(void)
|
||||
{
|
||||
return 0x100000U;
|
||||
}
|
||||
static inline u32 ast_ast1_control_carveoutlock_false_f(void)
|
||||
{
|
||||
return 0x0U;
|
||||
}
|
||||
static inline u32 ast_ast1_control_carveoutlock_defphysical_shift_v(void)
|
||||
{
|
||||
return 0x00000013U;
|
||||
}
|
||||
static inline u32 ast_ast1_control_carveoutlock_defvmindex_shift_v(void)
|
||||
{
|
||||
return 0x0000000fU;
|
||||
}
|
||||
static inline u32 ast_ast1_control_carveoutlock_defcarveoutid_shift_v(void)
|
||||
{
|
||||
return 0x00000005U;
|
||||
}
|
||||
static inline u32 ast_ast1_control_defsnoop_enable_f(void)
|
||||
{
|
||||
return 0x4U;
|
||||
}
|
||||
static inline u32 ast_ast1_control_defsnoop_disable_f(void)
|
||||
{
|
||||
return 0x0U;
|
||||
}
|
||||
static inline u32 ast_ast1_control_matcherrctl_no_decerr_f(void)
|
||||
{
|
||||
return 0x0U;
|
||||
}
|
||||
static inline u32 ast_ast1_control_matcherrctl_decerr_f(void)
|
||||
{
|
||||
return 0x2U;
|
||||
}
|
||||
static inline u32 ast_ast1_control_lock_true_f(void)
|
||||
{
|
||||
return 0x1U;
|
||||
}
|
||||
static inline u32 ast_ast1_control_lock_false_f(void)
|
||||
{
|
||||
return 0x0U;
|
||||
}
|
||||
static inline u32 ast_ast1_error_status_r(void)
|
||||
{
|
||||
return 0x50004U;
|
||||
}
|
||||
static inline u32 ast_ast1_error_addr_lo_r(void)
|
||||
{
|
||||
return 0x50008U;
|
||||
}
|
||||
static inline u32 ast_ast1_error_addr_hi_r(void)
|
||||
{
|
||||
return 0x5000cU;
|
||||
}
|
||||
static inline u32 ast_ast1_streamid_ctl_0_r(void)
|
||||
{
|
||||
return 0x50020U;
|
||||
}
|
||||
static inline u32 ast_ast1_streamid_ctl_0_write_mask_v(void)
|
||||
{
|
||||
return 0x0000ff01U;
|
||||
}
|
||||
static inline u32 ast_ast1_streamid_ctl_0_streamid_shift_v(void)
|
||||
{
|
||||
return 0x00000008U;
|
||||
}
|
||||
static inline u32 ast_ast1_streamid_ctl_0_enable_enable_f(void)
|
||||
{
|
||||
return 0x1U;
|
||||
}
|
||||
static inline u32 ast_ast1_streamid_ctl_0_enable_disable_f(void)
|
||||
{
|
||||
return 0x0U;
|
||||
}
|
||||
static inline u32 ast_ast1_streamid_ctl_1_r(void)
|
||||
{
|
||||
return 0x50024U;
|
||||
}
|
||||
static inline u32 ast_ast1_streamid_ctl_1_write_mask_v(void)
|
||||
{
|
||||
return 0x0000ff01U;
|
||||
}
|
||||
static inline u32 ast_ast1_streamid_ctl_1_streamid_shift_v(void)
|
||||
{
|
||||
return 0x00000008U;
|
||||
}
|
||||
static inline u32 ast_ast1_streamid_ctl_1_enable_enable_f(void)
|
||||
{
|
||||
return 0x1U;
|
||||
}
|
||||
static inline u32 ast_ast1_streamid_ctl_1_enable_disable_f(void)
|
||||
{
|
||||
return 0x0U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_0_slave_base_lo_r(void)
|
||||
{
|
||||
return 0x50100U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_0_slave_base_lo_slvbase_shift_v(void)
|
||||
{
|
||||
return 0x0000000cU;
|
||||
}
|
||||
static inline u32 ast_ast1_region_0_slave_base_lo_write_mask_v(void)
|
||||
{
|
||||
return 0xfffff001U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_0_slave_base_lo_enable_true_f(void)
|
||||
{
|
||||
return 0x1U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_0_slave_base_lo_enable_false_f(void)
|
||||
{
|
||||
return 0x0U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_0_slave_base_hi_r(void)
|
||||
{
|
||||
return 0x50104U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_0_mask_lo_r(void)
|
||||
{
|
||||
return 0x50108U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_0_mask_lo_write_mask_v(void)
|
||||
{
|
||||
return 0xfffff000U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_0_mask_hi_r(void)
|
||||
{
|
||||
return 0x5010cU;
|
||||
}
|
||||
static inline u32 ast_ast1_region_0_mask_hi_write_mask_v(void)
|
||||
{
|
||||
return 0xffffffffU;
|
||||
}
|
||||
static inline u32 ast_ast1_region_0_master_base_lo_r(void)
|
||||
{
|
||||
return 0x50110U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_0_master_base_lo_write_mask_v(void)
|
||||
{
|
||||
return 0xfffff000U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_0_master_base_hi_r(void)
|
||||
{
|
||||
return 0x50114U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_0_control_r(void)
|
||||
{
|
||||
return 0x50118U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_0_control_write_mask_v(void)
|
||||
{
|
||||
return 0x000f83e5U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_0_control_physical_shift_v(void)
|
||||
{
|
||||
return 0x00000013U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_0_control_vmindex_shift_v(void)
|
||||
{
|
||||
return 0x0000000fU;
|
||||
}
|
||||
static inline u32 ast_ast1_region_0_control_carveoutid_shift_v(void)
|
||||
{
|
||||
return 0x00000005U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_0_control_snoop_enable_f(void)
|
||||
{
|
||||
return 0x4U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_0_control_snoop_disable_f(void)
|
||||
{
|
||||
return 0x0U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_0_control_lock_true_f(void)
|
||||
{
|
||||
return 0x1U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_0_control_lock_false_f(void)
|
||||
{
|
||||
return 0x0U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_1_slave_base_lo_r(void)
|
||||
{
|
||||
return 0x50120U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_1_slave_base_hi_r(void)
|
||||
{
|
||||
return 0x50124U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_1_mask_lo_r(void)
|
||||
{
|
||||
return 0x50128U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_1_mask_hi_r(void)
|
||||
{
|
||||
return 0x5012cU;
|
||||
}
|
||||
static inline u32 ast_ast1_region_1_master_base_lo_r(void)
|
||||
{
|
||||
return 0x50130U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_1_master_base_hi_r(void)
|
||||
{
|
||||
return 0x50134U;
|
||||
}
|
||||
static inline u32 ast_ast1_region_1_control_r(void)
|
||||
{
|
||||
return 0x50138U;
|
||||
}
|
||||
#endif
|
||||
85
drivers/platform/tegra/dce/include/hw/hw_evp_dce.h
Normal file
85
drivers/platform/tegra/dce/include/hw/hw_evp_dce.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020, NVIDIA CORPORATION. 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
* Function naming determines intended use:
|
||||
*
|
||||
* <x>_r(void) : Returns the offset for register <x>.
|
||||
*
|
||||
* <x>_o(void) : Returns the offset for element <x>.
|
||||
*
|
||||
* <x>_w(void) : Returns the word offset for word (4 byte) element <x>.
|
||||
*
|
||||
* <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits.
|
||||
*
|
||||
* <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted
|
||||
* and masked to place it at field <y> of register <x>. This value
|
||||
* can be |'d with others to produce a full register value for
|
||||
* register <x>.
|
||||
*
|
||||
* <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This
|
||||
* value can be ~'d and then &'d to clear the value of field <y> for
|
||||
* register <x>.
|
||||
*
|
||||
* <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted
|
||||
* to place it at field <y> of register <x>. This value can be |'d
|
||||
* with others to produce a full register value for <x>.
|
||||
*
|
||||
* <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register
|
||||
* <x> value 'r' after being shifted to place its LSB at bit 0.
|
||||
* This value is suitable for direct comparison with other unshifted
|
||||
* values appropriate for use in field <y> of register <x>.
|
||||
*
|
||||
* <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for
|
||||
* field <y> of register <x>. This value is suitable for direct
|
||||
* comparison with unshifted values appropriate for use in field <y>
|
||||
* of register <x>.
|
||||
*/
|
||||
#ifndef HW_EVP_DCE_H
|
||||
#define HW_EVP_DCE_H
|
||||
|
||||
static inline u32 evp_reset_addr_r(void)
|
||||
{
|
||||
return 0x20U;
|
||||
}
|
||||
static inline u32 evp_undef_addr_r(void)
|
||||
{
|
||||
return 0x4U;
|
||||
}
|
||||
static inline u32 evp_swi_addr_r(void)
|
||||
{
|
||||
return 0x28U;
|
||||
}
|
||||
static inline u32 evp_prefetch_abort_addr_r(void)
|
||||
{
|
||||
return 0x2cU;
|
||||
}
|
||||
static inline u32 evp_data_abort_addr_r(void)
|
||||
{
|
||||
return 0x30U;
|
||||
}
|
||||
static inline u32 evp_rsvd_addr_r(void)
|
||||
{
|
||||
return 0x34U;
|
||||
}
|
||||
static inline u32 evp_irq_addr_r(void)
|
||||
{
|
||||
return 0x38U;
|
||||
}
|
||||
static inline u32 evp_fiq_addr_r(void)
|
||||
{
|
||||
return 0x3cU;
|
||||
}
|
||||
#endif
|
||||
233
drivers/platform/tegra/dce/include/hw/hw_hsp_dce.h
Normal file
233
drivers/platform/tegra/dce/include/hw/hw_hsp_dce.h
Normal file
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020, NVIDIA CORPORATION. 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
* Function naming determines intended use:
|
||||
*
|
||||
* <x>_r(void) : Returns the offset for register <x>.
|
||||
*
|
||||
* <x>_o(void) : Returns the offset for element <x>.
|
||||
*
|
||||
* <x>_w(void) : Returns the word offset for word (4 byte) element <x>.
|
||||
*
|
||||
* <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits.
|
||||
*
|
||||
* <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted
|
||||
* and masked to place it at field <y> of register <x>. This value
|
||||
* can be |'d with others to produce a full register value for
|
||||
* register <x>.
|
||||
*
|
||||
* <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This
|
||||
* value can be ~'d and then &'d to clear the value of field <y> for
|
||||
* register <x>.
|
||||
*
|
||||
* <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted
|
||||
* to place it at field <y> of register <x>. This value can be |'d
|
||||
* with others to produce a full register value for <x>.
|
||||
*
|
||||
* <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register
|
||||
* <x> value 'r' after being shifted to place its LSB at bit 0.
|
||||
* This value is suitable for direct comparison with other unshifted
|
||||
* values appropriate for use in field <y> of register <x>.
|
||||
*
|
||||
* <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for
|
||||
* field <y> of register <x>. This value is suitable for direct
|
||||
* comparison with unshifted values appropriate for use in field <y>
|
||||
* of register <x>.
|
||||
*/
|
||||
#ifndef HW_HSP_DCE_H
|
||||
#define HW_HSP_DCE_H
|
||||
|
||||
static inline u32 hsp_int_ie0_r(void)
|
||||
{
|
||||
return 0x150100U;
|
||||
}
|
||||
static inline u32 hsp_int_ie1_r(void)
|
||||
{
|
||||
return 0x150104U;
|
||||
}
|
||||
static inline u32 hsp_int_ie2_r(void)
|
||||
{
|
||||
return 0x150108U;
|
||||
}
|
||||
static inline u32 hsp_int_ie3_r(void)
|
||||
{
|
||||
return 0x15010cU;
|
||||
}
|
||||
static inline u32 hsp_int_ie4_r(void)
|
||||
{
|
||||
return 0x150110U;
|
||||
}
|
||||
static inline u32 hsp_int_ie5_r(void)
|
||||
{
|
||||
return 0x150114U;
|
||||
}
|
||||
static inline u32 hsp_int_ie6_r(void)
|
||||
{
|
||||
return 0x150118U;
|
||||
}
|
||||
static inline u32 hsp_int_ie7_r(void)
|
||||
{
|
||||
return 0x15011cU;
|
||||
}
|
||||
static inline u32 hsp_int_ir_r(void)
|
||||
{
|
||||
return 0x150304U;
|
||||
}
|
||||
static inline u32 hsp_sm0_r(void)
|
||||
{
|
||||
return 0x160000U;
|
||||
}
|
||||
static inline u32 hsp_sm0_full_int_ie_r(void)
|
||||
{
|
||||
return 0x160004U;
|
||||
}
|
||||
static inline u32 hsp_sm0_empty_int_ie_r(void)
|
||||
{
|
||||
return 0x160008U;
|
||||
}
|
||||
static inline u32 hsp_sm1_r(void)
|
||||
{
|
||||
return 0x168000U;
|
||||
}
|
||||
static inline u32 hsp_sm1_full_int_ie_r(void)
|
||||
{
|
||||
return 0x168004U;
|
||||
}
|
||||
static inline u32 hsp_sm1_empty_int_ie_r(void)
|
||||
{
|
||||
return 0x168008U;
|
||||
}
|
||||
static inline u32 hsp_sm2_r(void)
|
||||
{
|
||||
return 0x170000U;
|
||||
}
|
||||
static inline u32 hsp_sm2_full_int_ie_r(void)
|
||||
{
|
||||
return 0x170004U;
|
||||
}
|
||||
static inline u32 hsp_sm2_empty_int_ie_r(void)
|
||||
{
|
||||
return 0x170008U;
|
||||
}
|
||||
static inline u32 hsp_sm3_r(void)
|
||||
{
|
||||
return 0x178000U;
|
||||
}
|
||||
static inline u32 hsp_sm3_full_int_ie_r(void)
|
||||
{
|
||||
return 0x178004U;
|
||||
}
|
||||
static inline u32 hsp_sm3_empty_int_ie_r(void)
|
||||
{
|
||||
return 0x178008U;
|
||||
}
|
||||
static inline u32 hsp_sm4_r(void)
|
||||
{
|
||||
return 0x180000U;
|
||||
}
|
||||
static inline u32 hsp_sm4_full_int_ie_r(void)
|
||||
{
|
||||
return 0x180004U;
|
||||
}
|
||||
static inline u32 hsp_sm4_empty_int_ie_r(void)
|
||||
{
|
||||
return 0x180008U;
|
||||
}
|
||||
static inline u32 hsp_sm5_r(void)
|
||||
{
|
||||
return 0x188000U;
|
||||
}
|
||||
static inline u32 hsp_sm5_full_int_ie_r(void)
|
||||
{
|
||||
return 0x188004U;
|
||||
}
|
||||
static inline u32 hsp_sm5_empty_int_ie_r(void)
|
||||
{
|
||||
return 0x188008U;
|
||||
}
|
||||
static inline u32 hsp_sm6_r(void)
|
||||
{
|
||||
return 0x190000U;
|
||||
}
|
||||
static inline u32 hsp_sm6_full_int_ie_r(void)
|
||||
{
|
||||
return 0x190004U;
|
||||
}
|
||||
static inline u32 hsp_sm6_empty_int_ie_r(void)
|
||||
{
|
||||
return 0x190008U;
|
||||
}
|
||||
static inline u32 hsp_sm7_r(void)
|
||||
{
|
||||
return 0x198000U;
|
||||
}
|
||||
static inline u32 hsp_sm7_full_int_ie_r(void)
|
||||
{
|
||||
return 0x198004U;
|
||||
}
|
||||
static inline u32 hsp_sm7_empty_int_ie_r(void)
|
||||
{
|
||||
return 0x198008U;
|
||||
}
|
||||
static inline u32 hsp_ss0_state_r(void)
|
||||
{
|
||||
return 0x1a0000U;
|
||||
}
|
||||
static inline u32 hsp_ss0_set_r(void)
|
||||
{
|
||||
return 0x1a0004U;
|
||||
}
|
||||
static inline u32 hsp_ss0_clr_r(void)
|
||||
{
|
||||
return 0x1a0008U;
|
||||
}
|
||||
static inline u32 hsp_ss1_state_r(void)
|
||||
{
|
||||
return 0x1b0000U;
|
||||
}
|
||||
static inline u32 hsp_ss1_set_r(void)
|
||||
{
|
||||
return 0x1b0004U;
|
||||
}
|
||||
static inline u32 hsp_ss1_clr_r(void)
|
||||
{
|
||||
return 0x1b0008U;
|
||||
}
|
||||
static inline u32 hsp_ss2_state_r(void)
|
||||
{
|
||||
return 0x1c0000U;
|
||||
}
|
||||
static inline u32 hsp_ss2_set_r(void)
|
||||
{
|
||||
return 0x1c0004U;
|
||||
}
|
||||
static inline u32 hsp_ss2_clr_r(void)
|
||||
{
|
||||
return 0x1c0008U;
|
||||
}
|
||||
static inline u32 hsp_ss3_state_r(void)
|
||||
{
|
||||
return 0x1d0000U;
|
||||
}
|
||||
static inline u32 hsp_ss3_set_r(void)
|
||||
{
|
||||
return 0x1d0004U;
|
||||
}
|
||||
static inline u32 hsp_ss3_clr_r(void)
|
||||
{
|
||||
return 0x1d0008U;
|
||||
}
|
||||
#endif
|
||||
65
drivers/platform/tegra/dce/include/hw/hw_pm_dce.h
Normal file
65
drivers/platform/tegra/dce/include/hw/hw_pm_dce.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020, NVIDIA CORPORATION. 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
* Function naming determines intended use:
|
||||
*
|
||||
* <x>_r(void) : Returns the offset for register <x>.
|
||||
*
|
||||
* <x>_o(void) : Returns the offset for element <x>.
|
||||
*
|
||||
* <x>_w(void) : Returns the word offset for word (4 byte) element <x>.
|
||||
*
|
||||
* <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits.
|
||||
*
|
||||
* <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted
|
||||
* and masked to place it at field <y> of register <x>. This value
|
||||
* can be |'d with others to produce a full register value for
|
||||
* register <x>.
|
||||
*
|
||||
* <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This
|
||||
* value can be ~'d and then &'d to clear the value of field <y> for
|
||||
* register <x>.
|
||||
*
|
||||
* <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted
|
||||
* to place it at field <y> of register <x>. This value can be |'d
|
||||
* with others to produce a full register value for <x>.
|
||||
*
|
||||
* <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register
|
||||
* <x> value 'r' after being shifted to place its LSB at bit 0.
|
||||
* This value is suitable for direct comparison with other unshifted
|
||||
* values appropriate for use in field <y> of register <x>.
|
||||
*
|
||||
* <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for
|
||||
* field <y> of register <x>. This value is suitable for direct
|
||||
* comparison with unshifted values appropriate for use in field <y>
|
||||
* of register <x>.
|
||||
*/
|
||||
#ifndef HW_PM_DCE_H
|
||||
#define HW_PM_DCE_H
|
||||
|
||||
static inline u32 pm_r5_ctrl_r(void)
|
||||
{
|
||||
return 0x1f0040U;
|
||||
}
|
||||
static inline u32 pm_r5_ctrl_fwloaddone_halted_f(void)
|
||||
{
|
||||
return 0x0U;
|
||||
}
|
||||
static inline u32 pm_r5_ctrl_fwloaddone_done_f(void)
|
||||
{
|
||||
return 0x2U;
|
||||
}
|
||||
#endif
|
||||
183
drivers/platform/tegra/dce/include/interface/dce-admin-cmds.h
Normal file
183
drivers/platform/tegra/dce/include/interface/dce-admin-cmds.h
Normal file
@@ -0,0 +1,183 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright (c) 2018-2023 NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DCE_ADMIN_CMDS_H
|
||||
#define DCE_ADMIN_CMDS_H
|
||||
|
||||
#include <interface/dce-types.h>
|
||||
#include <interface/dce-admin-perf-stats.h>
|
||||
|
||||
/*
|
||||
* Version of the ADMIN command interface.
|
||||
*
|
||||
* This MUST be updated any time any changes are made to the ADMIN
|
||||
* commands.
|
||||
*
|
||||
* To keep things simple, this value should be incremented by 1 each
|
||||
* time changes are made.
|
||||
*/
|
||||
#define DCE_ADMIN_VERSION 3
|
||||
|
||||
#define DCE_ADMIN_CMD_SIZE sizeof(struct dce_admin_ipc_cmd)
|
||||
#define DCE_ADMIN_RESP_SIZE sizeof(struct dce_admin_ipc_resp)
|
||||
|
||||
#define DCE_ADMIN_CMD_CHAN_FSIZE max(DCE_ADMIN_CMD_SIZE, \
|
||||
DCE_ADMIN_RESP_SIZE)
|
||||
|
||||
#define DCE_ADMIN_CMD_MAX_NFRAMES 4
|
||||
|
||||
#define DCE_ADMIN_CMD_VERSION 0x00U // returns version of interface
|
||||
#define DCE_ADMIN_CMD_HOST_VERSION 0x01U // host supplied version
|
||||
#define DCE_ADMIN_CMD_GET_FW_VERSION 0x02U // return FW version info
|
||||
#define DCE_ADMIN_CMD_ECHO 0x03U // echo data back to CCPLEX
|
||||
#define DCE_ADMIN_CMD_MEM_MAP 0x04U // map a region of memory
|
||||
#define DCE_ADMIN_CMD_MEM_INFO 0x05U // return info about a region
|
||||
#define DCE_ADMIN_CMD_IPC_INFO 0x06U // return IPC chan info
|
||||
#define DCE_ADMIN_CMD_IPC_CREATE 0x07U // create an IPC channel
|
||||
#define DCE_ADMIN_CMD_PREPARE_SC7 0x08U // prepare to enter SC7
|
||||
#define DCE_ADMIN_CMD_ENTER_SC7 0x09U // enter SC7
|
||||
#define DCE_ADMIN_CMD_SET_LOGGING 0x0AU // set logging level
|
||||
#define DCE_ADMIN_CMD_GET_LOG_INFO 0x0BU // get current log info
|
||||
#define DCE_ADMIN_CMD_LOCK_CHANGES 0x0CU // lock creating new channels
|
||||
// and changing memory areas
|
||||
#define DCE_ADMIN_CMD_CODE_COVERAGE_START 0x0DU // start collecting code
|
||||
// coverage data
|
||||
#define DCE_ADMIN_CMD_CODE_COVERAGE_STOP 0x0EU // stop collecting code
|
||||
// coverage data
|
||||
#define DCE_ADMIN_CMD_PERF_START 0x0FU // start collecting perf data
|
||||
#define DCE_ADMIN_CMD_PERF_STOP 0x10U // stop collecting perf data
|
||||
#define DCE_ADMIN_CMD_INT_TEST_START 0x11U // start internal tests
|
||||
#define DCE_ADMIN_CMD_INT_TEST_STOP 0x12U // stop internal tests and return status
|
||||
#define DCE_ADMIN_CMD_EXT_TEST 0x13U // run external test (blocking call)
|
||||
#define DCE_ADMIN_CMD_DEBUG 0x14U // debug command
|
||||
#define DCE_ADMIN_CMD_RM_BOOTSTRAP 0x15U // tell RM to "bootstrap"
|
||||
#define DCE_ADMIN_CMD_PERF_RESULTS 0x16U // copy out the perf results
|
||||
#define DCE_ADMIN_CMD_PERF_GET_EVENTS 0x17U // get perf events
|
||||
#define DCE_ADMIN_CMD_PERF_CLEAR_EVENTS 0x18U // clear perf events
|
||||
|
||||
#define DCE_ADMIN_CMD_NEXT 0x19U // must be last command ID + 1
|
||||
|
||||
struct dce_admin_version_info {
|
||||
uint32_t version;
|
||||
};
|
||||
|
||||
struct dce_admin_fw_version_info {
|
||||
uint32_t bootstrap_interface;
|
||||
uint32_t admin_interface;
|
||||
uint32_t driver_headers;
|
||||
uint32_t core_interface;
|
||||
uint8_t fw_version[4];
|
||||
uint32_t gcid_revision;
|
||||
uint8_t safertos_major;
|
||||
uint8_t safertos_minor;
|
||||
};
|
||||
|
||||
struct dce_admin_echo {
|
||||
uint32_t data;
|
||||
};
|
||||
|
||||
enum dce_admin_ext_test {
|
||||
DCE_ADMIN_EXT_TEST_ALU = 0U,
|
||||
DCE_ADMIN_EXT_TEST_DMA = 1U,
|
||||
};
|
||||
struct dce_admin_ext_test_args {
|
||||
enum dce_admin_ext_test test;
|
||||
};
|
||||
|
||||
struct dce_admin_log_args {
|
||||
uint32_t log_enable;
|
||||
uint32_t log_level;
|
||||
};
|
||||
|
||||
struct dce_admin_mem_args {
|
||||
uint32_t region;
|
||||
dce_iova iova;
|
||||
uint32_t length;
|
||||
uint32_t sid;
|
||||
};
|
||||
|
||||
struct dce_admin_ipc_info_args {
|
||||
uint32_t type;
|
||||
};
|
||||
|
||||
struct dce_admin_ipc_signal {
|
||||
uint32_t signal_type;
|
||||
union {
|
||||
uint32_t mailbox;
|
||||
struct {
|
||||
uint32_t doorbell_num;
|
||||
uint32_t doorbell_bit_num;
|
||||
} doorbell;
|
||||
} signal;
|
||||
uint32_t semaphore;
|
||||
uint32_t semaphore_bit_num;
|
||||
};
|
||||
|
||||
struct dce_admin_ipc_info {
|
||||
uint32_t type;
|
||||
uint32_t flags;
|
||||
uint32_t mem_region;
|
||||
dce_iova rd_iova;
|
||||
dce_iova wr_iova;
|
||||
uint32_t fsize;
|
||||
uint32_t n_frames;
|
||||
struct dce_admin_ipc_signal signal_from_dce;
|
||||
struct dce_admin_ipc_signal signal_to_dce;
|
||||
};
|
||||
|
||||
struct dce_admin_ipc_create_args {
|
||||
uint32_t type;
|
||||
dce_iova rd_iova;
|
||||
dce_iova wr_iova;
|
||||
uint32_t fsize;
|
||||
uint32_t n_frames;
|
||||
};
|
||||
|
||||
struct dce_admin_ipc_cmd {
|
||||
uint32_t cmd;
|
||||
union {
|
||||
struct dce_admin_version_info version;
|
||||
struct dce_admin_echo echo;
|
||||
struct dce_admin_ext_test_args ext_test;
|
||||
struct dce_admin_log_args log;
|
||||
struct dce_admin_ipc_info_args ipc_info;
|
||||
struct dce_admin_mem_args mem_map;
|
||||
struct dce_admin_ipc_create_args ipc_create;
|
||||
struct dce_admin_perf_args perf;
|
||||
} args;
|
||||
};
|
||||
|
||||
struct dce_admin_ipc_resp {
|
||||
uint32_t error;
|
||||
union {
|
||||
struct dce_admin_version_info version;
|
||||
struct dce_admin_echo echo;
|
||||
struct dce_admin_log_args log;
|
||||
struct dce_admin_ipc_info ipc;
|
||||
struct dce_admin_mem_args mem_info;
|
||||
struct dce_admin_fw_version_info fw_version;
|
||||
struct dce_admin_perf_stats_info perf;
|
||||
} args;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,138 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright (c) 2023 NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DCE_ADMIN_PERF_STATS_H
|
||||
#define DCE_ADMIN_PERF_STATS_H
|
||||
|
||||
/*
|
||||
* Values for stats field
|
||||
*/
|
||||
#define DCE_ADMIN_PERF_STATS_SCHED 0x0001
|
||||
#define DCE_ADMIN_PERF_STATS_CACHE 0x0002
|
||||
#define DCE_ADMIN_PERF_STATS_IEXEC 0x0003
|
||||
#define DCE_ADMIN_PERF_STATS_MMIO 0x0004
|
||||
#define DCE_ADMIN_PERF_STATS_ALL 0xFFFF
|
||||
|
||||
/*
|
||||
* Values for clear field
|
||||
*/
|
||||
#define DCE_ADMIN_PERF_CLEAR_RETAIN 0U
|
||||
#define DCE_ADMIN_PERF_CLEAR_CLEAR 1U
|
||||
|
||||
#define DCE_ADMIN_EVENT_CLEAR_RETAIN 0U
|
||||
#define DCE_ADMIN_EVENT_CLEAR_CLEAR 1U
|
||||
|
||||
struct dce_admin_perf_cmd_args {
|
||||
uint32_t enable; // Enable stats capture through Bit-Mask
|
||||
uint32_t clear; // Clear all event stats
|
||||
};
|
||||
|
||||
struct dce_admin_perf_args {
|
||||
struct dce_admin_perf_cmd_args perf_cmd;
|
||||
struct dce_admin_perf_cmd_args event_cmd;
|
||||
};
|
||||
|
||||
/*
|
||||
* Task related defines for perf stats
|
||||
*/
|
||||
#define DCE_ADMIN_PERF_ADMIN_TASK 0U
|
||||
#define DCE_ADMIN_PERF_RM_TASK 1U
|
||||
#define DCE_ADMIN_PERF_PRINT_TASK 2U
|
||||
#define DCE_ADMIN_PERF_TCU_TASK 3U
|
||||
#define DCE_ADMIN_PERF_IDLE_TASK 4U
|
||||
// Change the active task number on adding more tasks
|
||||
#define DCE_ADMIN_PERF_ACTIVE_TASKS_NUM 5U
|
||||
// Max number of tasks in perf stats capture
|
||||
#define DCE_ADMIN_PERF_NUM_TASKS 10U
|
||||
// Task name length
|
||||
#define DCE_ADMIN_TASK_NAME_LEN 16U
|
||||
|
||||
struct dce_admin_stat_avg {
|
||||
uint64_t accumulate; // accumulated delta times
|
||||
uint64_t iterations;
|
||||
uint64_t min;
|
||||
uint64_t max;
|
||||
};
|
||||
|
||||
struct dce_admin_task_stats {
|
||||
const char name[DCE_ADMIN_TASK_NAME_LEN]; // task name
|
||||
uint64_t init; // how long to run init code
|
||||
uint64_t ready; // how long for task to be ready
|
||||
uint64_t ready_time; // time when task became ready
|
||||
uint64_t dcache_misses; // dcaches missed count accumulated within this task
|
||||
uint64_t inst_exec; // instruction execution accumulated
|
||||
uint64_t mmio_req; // memory request accumulated
|
||||
struct dce_admin_stat_avg sleep;
|
||||
struct dce_admin_stat_avg run;
|
||||
struct dce_admin_stat_avg run_context; // running context
|
||||
};
|
||||
|
||||
struct dce_admin_sched_stats {
|
||||
uint64_t start; // time collection started
|
||||
uint64_t end; // time collection stopped
|
||||
uint64_t context_switches; // overall context switches
|
||||
struct dce_admin_task_stats tasks[DCE_ADMIN_PERF_NUM_TASKS];
|
||||
};
|
||||
|
||||
/*
|
||||
* Performance monitor events and counters
|
||||
*/
|
||||
#define DCE_ADMIN_PM_EVT_DCACHE_MISSES 0U
|
||||
#define DCE_ADMIN_PM_EVT_INSTR_EXEC 1U
|
||||
#define DCE_ADMIN_PM_EVT_MEM_REQ 2U
|
||||
#define DCE_ADMIN_PM_EVT_COUNTERS 3U
|
||||
|
||||
struct dce_admin_pm_event_stats {
|
||||
uint64_t start; // time collection started
|
||||
uint64_t end; // time collection stopped
|
||||
uint64_t count; // Event counter accumulated
|
||||
};
|
||||
|
||||
struct dce_admin_perf_info {
|
||||
uint64_t tcm_ready; // tcm is ready/copied
|
||||
uint64_t sched_start; // scheduler started
|
||||
uint64_t ready_time; // signaled ready
|
||||
struct dce_admin_pm_event_stats pm_events[DCE_ADMIN_PM_EVT_COUNTERS];
|
||||
struct dce_admin_sched_stats sched;
|
||||
};
|
||||
|
||||
#define DCE_ADMIN_EVENT_NAME_LEN 32U // max length of an event name
|
||||
#define DCE_ADMIN_NUM_EVENTS 20U // s.b. same as DCE_NUM_EVENTS
|
||||
|
||||
struct dce_admin_event {
|
||||
char name[DCE_ADMIN_EVENT_NAME_LEN];
|
||||
struct dce_admin_stat_avg event;
|
||||
};
|
||||
|
||||
struct dce_admin_event_info {
|
||||
struct dce_admin_event events[DCE_ADMIN_NUM_EVENTS];
|
||||
};
|
||||
|
||||
|
||||
struct dce_admin_perf_stats_info {
|
||||
union {
|
||||
struct dce_admin_perf_info sched_stats;
|
||||
struct dce_admin_event_info events_stats;
|
||||
} info;
|
||||
};
|
||||
#endif
|
||||
39
drivers/platform/tegra/dce/include/interface/dce-bitops.h
Normal file
39
drivers/platform/tegra/dce/include/interface/dce-bitops.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DCE_BITOPS_H
|
||||
#define DCE_BITOPS_H
|
||||
|
||||
#define DCE_BIT(_b_) (((uint32_t)1U) << (_b_))
|
||||
|
||||
#define DCE_MASK(_msb_, _lsb_) \
|
||||
(((DCE_BIT(_msb_) - (uint32_t)1U) | \
|
||||
DCE_BIT(_msb_)) & (~(DCE_BIT(_lsb_) - (uint32_t)1U)))
|
||||
|
||||
#define DCE_EXTRACT(_x_, _msb_, _lsb_, _type_) \
|
||||
((_type_)((_type_)((_x_) & DCE_MASK(_msb_, _lsb_)) >> (_lsb_)))
|
||||
|
||||
#define DCE_INSERT(_x_, _msb_, _lsb_, _value_) \
|
||||
((((uint32_t)_x_) & DCE_MASK(_msb_, _lsb_)) | \
|
||||
((((uint32_t)_value_) << _lsb_) & DCE_MASK(_msb_, _lsb_)))
|
||||
|
||||
#endif
|
||||
123
drivers/platform/tegra/dce/include/interface/dce-boot-cmds.h
Normal file
123
drivers/platform/tegra/dce/include/interface/dce-boot-cmds.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DCE_BOOT_CMDS_H
|
||||
#define DCE_BOOT_CMDS_H
|
||||
|
||||
#include <interface/dce-bitops.h>
|
||||
|
||||
/*
|
||||
* Version of the bootstrap command interface.
|
||||
*
|
||||
* This MUST be updated any time any changes are made to the
|
||||
* bootstrap commands.
|
||||
*
|
||||
* To keep things simple, this value should be incremented by 1
|
||||
* each time changes are made.
|
||||
*/
|
||||
#define DCE_BOOT_CMD_VERSION_NUM 2
|
||||
|
||||
/*
|
||||
* Defines the various bootstrap commands to DCE.
|
||||
*
|
||||
* These commands are relatively simple and are mainly used to
|
||||
* communicate with DCE during initialization.
|
||||
*
|
||||
* The fundamental layout of a command is:
|
||||
* Bit(s) Field Description
|
||||
* 31:31 GO Signals to the DCE that a command is to be
|
||||
* processed
|
||||
* 30:27 COMMAND Identifies the command that the DCE is to
|
||||
* process
|
||||
* 26 RESERVED should be 0
|
||||
* 25 HILO 0 = PARM is 19:0 of address
|
||||
* 1 = PARM is 39:20 of address
|
||||
* 24 RDWR 0 = read header
|
||||
* 1 = write header
|
||||
* 23:20 RESERVED should be 0
|
||||
* 19:0 PARM Parameter to the command
|
||||
*
|
||||
* Once the command has been processed and the CCPLEX receives an interrupt
|
||||
* from DCE, the mailbox used will contain any information about the result
|
||||
* of the command.
|
||||
*
|
||||
* The commands are:
|
||||
*
|
||||
* DCE_BOOT_CMD_VERSION returns the version of the interface
|
||||
* DCE_BOOT_CMD_SET_SID sets the SID for a buffer
|
||||
* DCE_BOOT_CMD_CHANNEL_INIT initialize an IVC channel
|
||||
* DCE_BOOT_CMD_SET_ADDR set the channel address
|
||||
* DCE_BOOT_CMD_GET_FSIZE get the size of the frame
|
||||
* DCE_BOOT_CMD_SET_NFRAMES set the number of frames
|
||||
* DCE_BOOT_CMD_RESET causes DCE to reset to its initial state.
|
||||
* This does not cause DCE to reboot. It mearly
|
||||
* indicates that all of memory buffers for IPC
|
||||
* will be ignored and the CCPLEX will have to
|
||||
* re-establish the memory again.
|
||||
*
|
||||
* DCE_BOOT_CMD_LOCK locks the admin command interface. Requires
|
||||
* a full reset of DCE to unlock.
|
||||
*/
|
||||
#define DCE_BOOT_CMD_GO DCE_BIT(31)
|
||||
#define DCE_BOOT_CMD_SET(_x_, _v_) DCE_INSERT(_x_, 30, 27, _v_)
|
||||
#define DCE_BOOT_CMD_GET(_x_) DCE_EXTRACT(_x_, 30, 27, uint32_t)
|
||||
#define DCE_BOOT_CMD_SET_HILO(_x_, _v_) DCE_INSERT(_x_, 25, 25, _v_)
|
||||
#define DCE_BOOT_CMD_GET_HILO(_x_) DCE_EXTRACT(_x_, 25, 25, uint32_t)
|
||||
#define DCE_BOOT_CMD_SET_RDWR(_x_, _v_) DCE_INSERT(_x_, 24, 24, _v_)
|
||||
#define DCE_BOOT_CMD_GET_RDWR(_x_) DCE_EXTRACT(_x_, 24, 24, uint32_t)
|
||||
#define DCE_BOOT_CMD_PARM_SET(_x_, _v_) DCE_INSERT(_x_, 19, 0, _v_)
|
||||
#define DCE_BOOT_CMD_PARM_GET(_x_) DCE_EXTRACT(_x_, 19, 0, uint32_t)
|
||||
|
||||
/*
|
||||
* Commands
|
||||
*/
|
||||
#define DCE_BOOT_CMD_VERSION (0x00U)
|
||||
#define DCE_BOOT_CMD_SET_SID (0x01U)
|
||||
#define DCE_BOOT_CMD_CHANNEL_INIT (0x02U)
|
||||
#define DCE_BOOT_CMD_SET_ADDR (0x03U)
|
||||
#define DCE_BOOT_CMD_GET_FSIZE (0x04U)
|
||||
#define DCE_BOOT_CMD_SET_NFRAMES (0x05U)
|
||||
#define DCE_BOOT_CMD_RESET (0x06U)
|
||||
#define DCE_BOOT_CMD_LOCK (0x07U)
|
||||
#define DCE_BOOT_CMD_SET_AST_LENGTH (0x08U)
|
||||
#define DCE_BOOT_CMD_SET_AST_IOVA (0x09U)
|
||||
#define DCE_BOOT_CMD_SET_FSIZE (0x0AU)
|
||||
#define DCE_BOOT_CMD_UNUSED_11 (0x0BU)
|
||||
#define DCE_BOOT_CMD_UNUSED_12 (0x0CU)
|
||||
#define DCE_BOOT_CMD_UNUSED_13 (0x0DU)
|
||||
#define DCE_BOOT_CMD_UNUSED_14 (0x0EU)
|
||||
#define DCE_BOOT_CMD_UNUSED_15 (0x0FU)
|
||||
#define DCE_BOOT_CMD_NEXT (0x10U)
|
||||
|
||||
/*
|
||||
* Boot Command Errors
|
||||
*/
|
||||
#define DCE_BOOT_CMD_ERR_FLAG DCE_BIT(23)
|
||||
#define DCE_BOOT_CMD_NO_ERROR 0U
|
||||
#define DCE_BOOT_CMD_ERR_BAD_COMMAND (1U | DCE_BOOT_CMD_ERR_FLAG)
|
||||
#define DCE_BOOT_CMD_ERR_UNIMPLEMENTED (2U | DCE_BOOT_CMD_ERR_FLAG)
|
||||
#define DCE_BOOT_CMD_ERR_IPC_SETUP (3U | DCE_BOOT_CMD_ERR_FLAG)
|
||||
#define DCE_BOOT_CMD_ERR_INVALID_NFRAMES (4U | DCE_BOOT_CMD_ERR_FLAG)
|
||||
#define DCE_BOOT_CMD_ERR_IPC_CREATE (5U | DCE_BOOT_CMD_ERR_FLAG)
|
||||
#define DCE_BOOT_CMD_ERR_LOCKED (6U | DCE_BOOT_CMD_ERR_FLAG)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DCE_CORE_INTERFACE_ERRORS_H
|
||||
#define DCE_CORE_INTERFACE_ERRORS_H
|
||||
|
||||
#define DCE_ERR_CORE_SUCCESS 0U
|
||||
|
||||
#define DCE_ERR_CORE_NOT_IMPLEMENTED 1U
|
||||
#define DCE_ERR_CORE_SC7_SEQUENCE 2U
|
||||
#define DCE_ERR_CORE_RD_MEM_MAP 3U
|
||||
#define DCE_ERR_CORE_WR_MEM_MAP 4U
|
||||
#define DCE_ERR_CORE_IVC_INIT 5U
|
||||
#define DCE_ERR_CORE_MEM_NOT_FOUND 6U
|
||||
#define DCE_ERR_CORE_MEM_NOT_MAPPED 7U
|
||||
|
||||
#define DCE_ERR_CORE_VMINDEX_INVALID 8U
|
||||
#define DCE_ERR_CORE_VMINDEX_NO_AST_BASE 9U
|
||||
|
||||
#define DCE_ERR_CORE_MEM_ALREADY_MAPPED 10U
|
||||
|
||||
#define DCE_ERR_CORE_BAD_ADMIN_CMD 11U
|
||||
#define DCE_ERR_CORE_INTERFACE_LOCKED 12U
|
||||
#define DCE_ERR_CORE_INTERFACE_INCOMPATIBLE 13U
|
||||
|
||||
#define DCE_ERR_CORE_MEM_SIZE 14U
|
||||
|
||||
#define DCE_ERR_CORE_NULL_PTR 15U
|
||||
|
||||
#define DCE_ERR_CORE_TIMER_INVALID 16U
|
||||
#define DCE_ERR_CORE_TIMER_EXPIRED 17U
|
||||
|
||||
#define DCE_ERR_CORE_IPC_BAD_TYPE 18U
|
||||
#define DCE_ERR_CORE_IPC_NO_HANDLES 19U
|
||||
#define DCE_ERR_CORE_IPC_BAD_CHANNEL 20U
|
||||
#define DCE_ERR_CORE_IPC_CHAN_REGISTERED 21U
|
||||
#define DCE_ERR_CORE_IPC_BAD_HANDLE 22U
|
||||
#define DCE_ERR_CORE_IPC_MSG_TOO_LARGE 23U
|
||||
#define DCE_ERR_CORE_IPC_NO_BUFFERS 24U
|
||||
#define DCE_ERR_CORE_IPC_BAD_HEADER 25U
|
||||
#define DCE_ERR_CORE_IPC_IVC_INIT 26U
|
||||
#define DCE_ERR_CORE_IPC_NO_DATA 27U
|
||||
#define DCE_ERR_CORE_IPC_INVALID_SIGNAL 28U
|
||||
#define DCE_ERR_CORE_IPC_IVC_ERR 29U
|
||||
|
||||
#define DCE_ERR_CORE_MEM_BAD_REGION 30U
|
||||
|
||||
#define DCE_ERR_CORE_GPIO_INVALID_ID 31U
|
||||
#define DCE_ERR_CORE_GPIO_NO_SPACE 32U
|
||||
|
||||
#define DCE_ERR_CORE_RM_BOOTSTRAP 40U
|
||||
|
||||
#define DCE_ERR_CORE_IPC_SIGNAL_REGISTERED 50U
|
||||
|
||||
#define DCE_ERR_CORE_NOT_FOUND 60U
|
||||
#define DCE_ERR_CORE_NOT_INITIALIZED 61U
|
||||
|
||||
#define DCE_ERR_CORE_OTHER 9999U
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DCE_CORE_INTERFACE_IPC_TYPES_H
|
||||
#define DCE_CORE_INTERFACE_IPC_TYPES_H
|
||||
|
||||
|
||||
/*
|
||||
* Because this file is to be shared between DCE Core, RM and driver,
|
||||
* it must not include or reference anything that is not contained
|
||||
* in the following header files:
|
||||
* stdint.h
|
||||
* stddef.h
|
||||
* stdbool.h
|
||||
*/
|
||||
|
||||
typedef uint32_t dce_ipc_type_t;
|
||||
|
||||
#define DCE_IPC_TYPE_ADMIN ((dce_ipc_type_t)0U)
|
||||
#define DCE_IPC_TYPE_DISPRM ((dce_ipc_type_t)1U)
|
||||
#define DCE_IPC_TYPE_HDCP ((dce_ipc_type_t)2U)
|
||||
#define DCE_IPC_TYPE_RM_NOTIFY ((dce_ipc_type_t)3U)
|
||||
#define DCE_IPC_TYPE_BPMP ((dce_ipc_type_t)4U)
|
||||
#define DCE_IPC_TYPE_MAX ((dce_ipc_type_t)5U)
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DCE_DRIVER_HEADER_VERSION_H
|
||||
#define DCE_DRIVER_HEADER_VERSION_H
|
||||
|
||||
/*
|
||||
* Version of the headers shared between the driver and DCE FW.
|
||||
*
|
||||
* This MUST be updated any time any changes are made to the headers
|
||||
* that are shared between the driver and DCE FW.
|
||||
*
|
||||
* To keep things simple, this value should be incremented by 1 each
|
||||
* time changes are made.
|
||||
*/
|
||||
#define DCE_DRIVER_HEADER_VERSION 2
|
||||
|
||||
#endif
|
||||
125
drivers/platform/tegra/dce/include/interface/dce-interface.h
Normal file
125
drivers/platform/tegra/dce/include/interface/dce-interface.h
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DCE_INTERFACE_H
|
||||
#define DCE_INTERFACE_H
|
||||
|
||||
#include <interface/dce-bitops.h>
|
||||
|
||||
/*
|
||||
* XXX: TODO
|
||||
*
|
||||
* These should be defined in terms of the HW registers
|
||||
*/
|
||||
#define DCE_NUM_SEMA_REGS 4
|
||||
#define DCE_NUM_MBOX_REGS 8
|
||||
|
||||
/*
|
||||
* Symbolic definitions of the semaphore registers
|
||||
*/
|
||||
typedef uint32_t hsp_sema_t;
|
||||
|
||||
#define DCE_BOOT_SEMA (hsp_sema_t)0U
|
||||
|
||||
/*
|
||||
* Definitions for DCE_BOOT_SEMA
|
||||
*
|
||||
* Used to communicate bits of information between the OS and DCE
|
||||
*/
|
||||
|
||||
/*
|
||||
* Bits set by the OS and examined by the R5
|
||||
*/
|
||||
#define DCE_BOOT_INT DCE_BIT(31) // interrupt when DCE is ready
|
||||
#define DCE_WAIT_DEBUG DCE_BIT(30) // wait in debug loop
|
||||
#define DCE_SC7_RESUME DCE_BIT(29) // resume using saved SC7 state
|
||||
// rather than a full restart
|
||||
#define DCE_OS_BITMASK (DCE_BOOT_INT | DCE_WAIT_DEBUG | DCE_SC7_RESUME)
|
||||
|
||||
/*
|
||||
* Bits set by the R5 and examined by the OS
|
||||
*/
|
||||
#define DCE_BOOT_TCM_COPY DCE_BIT(15) // uCode has copied to TCM
|
||||
#define DCE_BOOT_HW_INIT DCE_BIT(14) // hardware init complete
|
||||
#define DCE_BOOT_MPU_INIT DCE_BIT(13) // MPU initialized
|
||||
#define DCE_BOOT_CACHE_INIT DCE_BIT(12) // cache initialized
|
||||
#define DCE_BOOT_R5_INIT DCE_BIT(11) // R5 initialized
|
||||
#define DCE_BOOT_DRIVER_INIT DCE_BIT(10) // driver init complete
|
||||
#define DCE_BOOT_MAIN_STARTED DCE_BIT(9) // main started
|
||||
#define DCE_BOOT_TASK_INIT_START DCE_BIT(8) // task initialization started
|
||||
#define DCE_BOOT_TASK_INIT_DONE DCE_BIT(7) // task initialization complete
|
||||
|
||||
#define DCE_HALTED DCE_BIT(1) // uCode has halted
|
||||
#define DCE_BOOT_COMPLETE DCE_BIT(0) // uCode boot has completed
|
||||
|
||||
/*
|
||||
* Symbolic definitions of the doorbell registers
|
||||
*/
|
||||
typedef uint32_t hsp_db_t;
|
||||
|
||||
/*
|
||||
* Symbolic definitions of the mailbox registers (rather than using 0-7)
|
||||
*/
|
||||
typedef uint32_t hsp_mbox_t;
|
||||
|
||||
#define DCE_MBOX_FROM_DCE_RM (hsp_mbox_t)0U // signal from RM IPC
|
||||
#define DCE_MBOX_TO_DCE_RM (hsp_mbox_t)1U // signal to RM IPC
|
||||
#define DCE_MBOX_FROM_DCE_RM_EVENT_NOTIFY (hsp_mbox_t)2U // signal to DCE for event notification
|
||||
#define DCE_MBOX_TO_DCE_RM_EVENT_NOTIFY (hsp_mbox_t)3U // signal from DCE for event notification IPC
|
||||
#define DCE_MBOX_FROM_DCE_ADMIN (hsp_mbox_t)4U // signal from DCE ADMIN IPC
|
||||
#define DCE_MBOX_TO_DCE_ADMIN (hsp_mbox_t)5U // signal to ADMIN IPC
|
||||
#define DCE_MBOX_BOOT_CMD (hsp_mbox_t)6U // boot commands
|
||||
#define DCE_MBOX_IRQ (hsp_mbox_t)7U // general interrupt/status
|
||||
/*
|
||||
* Generic interrupts & status from the DCE are reported in DCE_MBOX_IRQ
|
||||
*/
|
||||
#define DCE_IRQ_PENDING DCE_BIT(31)// interrupt is pending
|
||||
|
||||
#define DCE_IRQ_GET_STATUS_TYPE(_x_) DCE_EXTRACT(_x_, 30, 27, uint32_t)
|
||||
#define DCE_IRQ_SET_STATUS_TYPE(_x_) DCE_INSERT(0U, 30, 27, _x_)
|
||||
|
||||
#define DCE_IRQ_STATUS_TYPE_IRQ 0x0 // irq status
|
||||
#define DCE_IRQ_STATUS_TYPE_BOOT_CMD 0x1 // boot command status
|
||||
|
||||
#define NUM_DCE_IRQ_STATUS_TYPES 2
|
||||
|
||||
#define DCE_IRQ_GET_STATUS(_x_) DCE_EXTRACT(_x_, 23, 0, uint32_t)
|
||||
#define DCE_IRQ_SET_STATUS(_x_) DCE_INSERT(0U, 23, 0, _x_)
|
||||
|
||||
/*
|
||||
* Bits in status field when IRQ_STATUS_TYPE == IRQ_STATUS_TYPE_IRQ
|
||||
*/
|
||||
#define DCE_IRQ_READY DCE_BIT(23) // DCE is ready
|
||||
#define DCE_IRQ_LOG_OVERFLOW DCE_BIT(22) // trace log overflow
|
||||
#define DCE_IRQ_LOG_READY DCE_BIT(21) // trace log buffers available
|
||||
#define DCE_IRQ_CRASH_LOG DCE_BIT(20) // crash log available
|
||||
#define DCE_IRQ_ABORT DCE_BIT(19) // uCode abort occurred
|
||||
#define DCE_IRQ_SC7_ENTERED DCE_BIT(18) // DCE state saved
|
||||
// can be powered off
|
||||
|
||||
/*
|
||||
* MBOX contents for IPC are the same for all of the mailboxes that are
|
||||
* used for signaling IPC. Not all values will be useful for all mailboxes.
|
||||
*/
|
||||
#define DCE_IPC_IRQ_PENDING DCE_BIT(31) // interrupt is pending
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DCE_IPC_HEADER_H
|
||||
#define DCE_IPC_HEADER_H
|
||||
|
||||
struct dce_ipc_header {
|
||||
uint32_t length;
|
||||
};
|
||||
|
||||
#endif
|
||||
48
drivers/platform/tegra/dce/include/interface/dce-ipc-state.h
Normal file
48
drivers/platform/tegra/dce/include/interface/dce-ipc-state.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DCE_IPC_STATE_H
|
||||
#define DCE_IPC_STATE_H
|
||||
|
||||
#include <interface/dce-bitops.h>
|
||||
|
||||
/*
|
||||
* Flags used to denote the state of IPC data structures
|
||||
*/
|
||||
typedef uint32_t dce_ipc_flags_t;
|
||||
|
||||
#define DCE_IPC_FL_VALID ((dce_ipc_flags_t)DCE_BIT(0))
|
||||
#define DCE_IPC_FL_REGISTERED ((dce_ipc_flags_t)DCE_BIT(1))
|
||||
#define DCE_IPC_FL_INIT ((dce_ipc_flags_t)DCE_BIT(2))
|
||||
#define DCE_IPC_FL_READY ((dce_ipc_flags_t)DCE_BIT(3))
|
||||
#define DCE_IPC_FL_RM_ALLOWED ((dce_ipc_flags_t)DCE_BIT(4))
|
||||
#define DCE_IPC_FL_MSG_HEADER ((dce_ipc_flags_t)DCE_BIT(15))
|
||||
|
||||
/*
|
||||
* Different types of signal mechanisms
|
||||
*/
|
||||
typedef uint32_t dce_ipc_signal_type_t;
|
||||
|
||||
#define DCE_IPC_SIGNAL_MAILBOX ((dce_ipc_signal_type_t)0U)
|
||||
#define DCE_IPC_SIGNAL_DOORBELL ((dce_ipc_signal_type_t)1U)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DCE_MEMORY_IDS_H
|
||||
#define DCE_MEMORY_IDS_H
|
||||
|
||||
/*
|
||||
* Defines the varous memory IDs used for mapping memory regions
|
||||
* for DCE.
|
||||
*
|
||||
* XXX: TODO
|
||||
* Rename some of the IDs to better represent what they're used for
|
||||
*/
|
||||
|
||||
#define DCE_MAP_DRAM_ID 0U // FW DRAM
|
||||
#define DCE_MAP_BPMP_ID 1U // BPMP communications area
|
||||
#define DCE_MAP_CONFIG_DATA_ID 2U // device tree
|
||||
#define DCE_MAP_IPC_ID 3U // memory region for IPC
|
||||
#define DCE_MAP_MSG_ID 4U // extra: rename at some point
|
||||
#define DCE_MAP_UTILITY_ID 5U // extra: rename at some point
|
||||
#define DCE_MAP_RM_ID 6U // RM communications area
|
||||
#define DCE_MAP_RM_DATA_ID 7U // extra RM data area
|
||||
|
||||
#endif
|
||||
28
drivers/platform/tegra/dce/include/interface/dce-types.h
Normal file
28
drivers/platform/tegra/dce/include/interface/dce-types.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DCE_TYPES_H
|
||||
#define DCE_TYPES_H
|
||||
|
||||
typedef uint64_t dce_iova;
|
||||
|
||||
#endif
|
||||
86
include/linux/platform/tegra/dce/dce-client-ipc.h
Normal file
86
include/linux/platform/tegra/dce/dce-client-ipc.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020, NVIDIA CORPORATION. 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 TEGRA_DCE_CLIENT_IPC_H
|
||||
#define TEGRA_DCE_CLIENT_IPC_H
|
||||
|
||||
#define DCE_CLIENT_IPC_TYPE_CPU_RM 0U
|
||||
#define DCE_CLIENT_IPC_TYPE_HDCP_KMD 1U
|
||||
#define DCE_CLIENT_IPC_TYPE_RM_EVENT 2U
|
||||
#define DCE_CLIENT_IPC_TYPE_MAX 3U
|
||||
|
||||
#define DCE_CLIENT_MAX_IPC_MSG_SIZE 4096
|
||||
|
||||
/**
|
||||
* struct dce_ipc_message - Contains necessary info for an ipc msg.
|
||||
*
|
||||
* @tx : transmit message info
|
||||
* @rx : receive message info
|
||||
*/
|
||||
struct dce_ipc_message {
|
||||
struct {
|
||||
void *data;
|
||||
size_t size;
|
||||
} tx;
|
||||
struct {
|
||||
void *data;
|
||||
size_t size;
|
||||
} rx;
|
||||
};
|
||||
|
||||
/*
|
||||
* tegra_dce_client_ipc_callback_t - callback function to notify the
|
||||
* client when the CPU Driver receives an IPC from DCE for the client.
|
||||
*
|
||||
* @client_id: id that represents the corresponding client.
|
||||
* @interface_type: Interface on which the IPC was received.
|
||||
* @msg_length: Length of the message.
|
||||
* @msg_data: Message data.
|
||||
* @usr_ctx: Any user context if present.
|
||||
*/
|
||||
typedef void (*tegra_dce_client_ipc_callback_t)(u32 handle,
|
||||
u32 interface_type, u32 msg_length,
|
||||
void *msg_data, void *usr_ctx);
|
||||
|
||||
/*
|
||||
* tegra_dce_register_ipc_client() - used by clients to register with dce driver
|
||||
* @interface_type: Interface for which this client is expected to send rpcs and
|
||||
* receive callbacks.
|
||||
* @callback_fn: callback function to be called by DCE driver on receiving IPCs
|
||||
* from DCE on this interface.
|
||||
* @usr_ctx: Any user context if present.
|
||||
*
|
||||
* Return: valid client_id if no errors else corresponding error value.
|
||||
*/
|
||||
int tegra_dce_register_ipc_client(u32 interface_type,
|
||||
tegra_dce_client_ipc_callback_t callback_fn,
|
||||
void *usr_ctx, u32 *handlep);
|
||||
|
||||
/*
|
||||
* tegra_dce_unregister_client() - used by clients to unregister to dce driver
|
||||
* @client_id : ointer to client's data
|
||||
*
|
||||
* Return: 0 if no errors else corresponding error value.
|
||||
*/
|
||||
int tegra_dce_unregister_ipc_client(u32 handle);
|
||||
|
||||
/*
|
||||
* tegra_dce_client_ipc_send_recv() - used by clients to send rpcs to dce
|
||||
* @client_id : client_id registered with dce driver
|
||||
* @msg : message to be sent and received
|
||||
*
|
||||
* Return: 0 if no errors else corresponding error value.
|
||||
*/
|
||||
int tegra_dce_client_ipc_send_recv(u32 handle, struct dce_ipc_message *msg);
|
||||
|
||||
#endif
|
||||
94
include/trace/events/dce_events.h
Normal file
94
include/trace/events/dce_events.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2022, NVIDIA CORPORATION, All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that 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.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM dce_events
|
||||
|
||||
#if !defined(_TRACE_DCE_EVENTS_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||
#define _TRACE_DCE_EVENTS_H
|
||||
|
||||
#include <dce.h>
|
||||
#include <dce-ipc.h>
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
DECLARE_EVENT_CLASS(dce_ipc_events_notifier,
|
||||
TP_PROTO(struct tegra_dce *d, struct dce_ipc_channel *ch),
|
||||
TP_ARGS(d, ch),
|
||||
TP_STRUCT__entry(
|
||||
__field_struct(struct dce_ipc_channel *, ch)
|
||||
__field_struct(struct tegra_dce *, d)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->ch = ch;
|
||||
__entry->d = d;
|
||||
),
|
||||
TP_printk("Channel Type = [%u], Flags = [0x%x], Wait Type = [%u], Write Pos = [%u], Read Pos = [%u], Frame Size = [%u], "
|
||||
"No of Frames = [%u], Rx Iova = [0x%llx], Tx Iova = [0x%llx], Region Current Offset = [%u], Region Iova Base = [0x%llx], "
|
||||
"Region Size = [%lu] Region Base Address = [0x%p]",
|
||||
__entry->ch->ch_type, __entry->ch->flags, __entry->ch->w_type,
|
||||
__entry->ch->d_ivc.tx.position, __entry->ch->d_ivc.rx.position,
|
||||
__entry->ch->q_info.frame_sz, __entry->ch->q_info.nframes,
|
||||
__entry->ch->q_info.rx_iova, __entry->ch->q_info.tx_iova,
|
||||
__entry->d->d_ipc.region.s_offset, __entry->d->d_ipc.region.iova,
|
||||
__entry->d->d_ipc.region.size, __entry->d->d_ipc.region.base)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(dce_ipc_events_notifier, ivc_channel_init_complete,
|
||||
TP_PROTO(struct tegra_dce *d, struct dce_ipc_channel *ch),
|
||||
TP_ARGS(d, ch)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(dce_ipc_events_notifier, ivc_channel_reset_triggered,
|
||||
TP_PROTO(struct tegra_dce *d, struct dce_ipc_channel *ch),
|
||||
TP_ARGS(d, ch)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(dce_ipc_events_notifier, ivc_channel_reset_complete,
|
||||
TP_PROTO(struct tegra_dce *d, struct dce_ipc_channel *ch),
|
||||
TP_ARGS(d, ch)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(dce_ipc_events_notifier, ivc_send_req_received,
|
||||
TP_PROTO(struct tegra_dce *d, struct dce_ipc_channel *ch),
|
||||
TP_ARGS(d, ch)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(dce_ipc_events_notifier, ivc_send_complete,
|
||||
TP_PROTO(struct tegra_dce *d, struct dce_ipc_channel *ch),
|
||||
TP_ARGS(d, ch)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(dce_ipc_events_notifier, ivc_wait_complete,
|
||||
TP_PROTO(struct tegra_dce *d, struct dce_ipc_channel *ch),
|
||||
TP_ARGS(d, ch)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(dce_ipc_events_notifier, ivc_receive_req_received,
|
||||
TP_PROTO(struct tegra_dce *d, struct dce_ipc_channel *ch),
|
||||
TP_ARGS(d, ch)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(dce_ipc_events_notifier, ivc_receive_req_complete,
|
||||
TP_PROTO(struct tegra_dce *d, struct dce_ipc_channel *ch),
|
||||
TP_ARGS(d, ch)
|
||||
);
|
||||
|
||||
#endif /* _TRACE_DCE_EVENTS_H */
|
||||
|
||||
/* This part must be outside protection */
|
||||
#include <trace/define_trace.h>
|
||||
Reference in New Issue
Block a user