mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 17:25:35 +03:00
platform: tegra: dce: add dce kernel driver
For T23x, we have a separate R5 based cluster named as Display Controller Engine(DCE) to run our Display RM code. This driver will run on CPU with the following functionality: Via debugfs for test and bring-up purposes: 1. Reads the DCE firmware image into DRAM. 2. Sets up DCE AST to cover the DCE firmware image. 3. Sets up R5 reset vector to point to DCE firmware entry point 4. Brings DCE out of reset 5. Dumps various regsiters for debug In production env: 1. Manages interrupts to CPU from DCE 2. Uses bootstrap command interface to define Admin IPC 3. Locks down bootstrap command interface 4. Uses Admin IPC to define message IPC 5. Uses Admin IPC to define message IPC payload area 6. Uses Admin IPC to set IPC channels 6. Uses Admin IPC to define crashdump area (optional) 7. Provides IPC interfaces for any DCE Client running on CCPLEX including Display RM. 8. Uses Admin IPC to set logging level (optional) This patch puts a framework in place with the following features : 1. Firmware Loading 2. AST Configuration 3. DCE Reset with EVP Programming 4. Logging Infra 5. Debugfs Support 6. Interrupt Handling 7. Mailbox Programming 8. IPC Programming 9. DCE Client Interface 10. Ftrace Support for debug purposes Change-Id: Idd28cd9254706c7313f531fcadaa7024a5b344e7 Signed-off-by: Arun Swain <arswain@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-t23x/+/2289865 Reviewed-by: automaticguardword <automaticguardword@nvidia.com> Reviewed-by: Mahesh Kumar <mahkumar@nvidia.com> Reviewed-by: Santosh Galma <galmar@nvidia.com> Reviewed-by: Mitch Luban <mluban@nvidia.com> Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> GVS: Gerrit_Virtual_Submit Tested-by: Mahesh Kumar <mahkumar@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
committed by
Laxman Dewangan
parent
fe2085dcef
commit
606f03fbf2
31
drivers/platform/tegra/dce/Makefile
Normal file
31
drivers/platform/tegra/dce/Makefile
Normal file
@@ -0,0 +1,31 @@
|
||||
#
|
||||
# Display Controller Engine code.
|
||||
#
|
||||
GCOV_PROFILE := y
|
||||
|
||||
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
|
||||
obj-$(CONFIG_TEGRA_DCE) += tegra-dce.o
|
||||
|
||||
tegra-dce-y += \
|
||||
dce-ast.o \
|
||||
dce-reset.o \
|
||||
dce-hsp-smb.o \
|
||||
dce-hsp-ss.o \
|
||||
dce-worker.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-util-common.o \
|
||||
dce-debug.o
|
||||
|
||||
ccflags-y += -I$(srctree.nvidia-t23x)/drivers/platform/tegra/dce/include
|
||||
505
drivers/platform/tegra/dce/dce-admin.c
Normal file
505
drivers/platform/tegra/dce/dce-admin.c
Normal file
@@ -0,0 +1,505 @@
|
||||
/*
|
||||
* 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-mailbox.h>
|
||||
#include <dce-util-common.h>
|
||||
#include <dce-client-ipc-internal.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.
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
int dce_admin_ipc_wait(struct tegra_dce *d, u32 w_type)
|
||||
{
|
||||
int ret = 0;
|
||||
enum dce_worker_event_id_type event;
|
||||
|
||||
switch (w_type) {
|
||||
case DCE_IPC_WAIT_TYPE_SYNC:
|
||||
event = EVENT_ID_DCE_IPC_MESSAGE_SENT;
|
||||
break;
|
||||
case DCE_IPC_WAIT_TYPE_RPC:
|
||||
event = EVENT_ID_DCE_IPC_MESSAGE_SENT;
|
||||
break;
|
||||
default:
|
||||
dce_err(d, "Invalid wait type [%d]", w_type);
|
||||
break;
|
||||
}
|
||||
|
||||
dce_worker_thread_wait(d, event);
|
||||
|
||||
if (dce_worker_get_state(d)
|
||||
== STATE_DCE_WORKER_ABORTED)
|
||||
ret = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_admin_interface_isr - Isr for the CCPLEX<->DCE admin interface
|
||||
*
|
||||
* @d : Pointer to tegra_de struct.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
static void dce_admin_wakeup_ipc(struct tegra_dce *d)
|
||||
{
|
||||
enum dce_worker_event_id_type event = EVENT_ID_DCE_IPC_SIGNAL_RECEIVED;
|
||||
|
||||
dce_worker_thread_wakeup(d, 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_cl = false;
|
||||
bool wakeup_needed = false;
|
||||
|
||||
/**
|
||||
* TODO : Get rid of prints
|
||||
*/
|
||||
dce_info(d, "Signal Received : check if channel is ready [%d]",
|
||||
ch_type);
|
||||
|
||||
if (!(dce_ipc_channel_is_ready(d, ch_type))) {
|
||||
/**
|
||||
* The ivc channel is not ready yet. Exit
|
||||
* and wait for another signal from target.
|
||||
*/
|
||||
goto process_wakeup;
|
||||
}
|
||||
/**
|
||||
* TODO : Get rid of prints
|
||||
*/
|
||||
dce_info(d, "Signal Received : Channel in established state already : [%d]",
|
||||
ch_type);
|
||||
|
||||
wakeup_needed = (DCE_IPC_WAIT_TYPE_SYNC ==
|
||||
dce_ipc_get_cur_wait_type(d, ch_type));
|
||||
if (wakeup_needed) {
|
||||
/**
|
||||
* Handshake successful, wake up the
|
||||
* dce worker thread since it's waiting
|
||||
* for the synchronization to complete.
|
||||
*/
|
||||
goto process_wakeup;
|
||||
}
|
||||
/**
|
||||
* TODO : Get rid of prints
|
||||
*/
|
||||
dce_info(d, "Signal Received : Channel synchronized already : [%d]",
|
||||
ch_type);
|
||||
|
||||
/**
|
||||
* 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)
|
||||
wakeup_cl = (ch_type != DCE_IPC_CH_KMD_TYPE_ADMIN);
|
||||
|
||||
/**
|
||||
* TODO : Get rid of prints
|
||||
*/
|
||||
dce_info(d, "Signal Received : Data available : [%d] for channel: [%d]",
|
||||
wakeup_needed, ch_type);
|
||||
|
||||
process_wakeup:
|
||||
if (!wakeup_needed) {
|
||||
dce_info(d, "Spurious signal on channel: [%d]. Ignored...",
|
||||
ch_type);
|
||||
return;
|
||||
}
|
||||
if (!wakeup_cl)
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_channel_init:
|
||||
dce_ipc_free_region(d);
|
||||
err_ipc_reg_alloc:
|
||||
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_cmd_version_cmd - Sends DCE_ADMIN_CMD_VERSION cmd.
|
||||
*
|
||||
* @d - Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return - 0 if successful
|
||||
*/
|
||||
int dce_admin_send_msg(struct tegra_dce *d, struct dce_ipc_message *msg)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
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");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
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, "error value : [0x%x]", resp_msg->error);
|
||||
dce_info(d, "version number : [0x%x]", ver_info->version);
|
||||
|
||||
out:
|
||||
/**
|
||||
* TODO : Add more error handling here
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* TODO : Get rid of prints
|
||||
*/
|
||||
dce_err(d, "value of q_struct for type [%d]", ipc_info->type);
|
||||
dce_err(d, "ch->q_info.nframes : [%u]", ipc_info->n_frames);
|
||||
dce_err(d, "ch->q_info.frame_sz: [%u]", ipc_info->fsize);
|
||||
dce_err(d, "ch->q_info.rx_iova: [0x%llx]", ipc_info->wr_iova);
|
||||
dce_err(d, "ch->q_info.tx_iova: [0x%llx]", ipc_info->rd_iova);
|
||||
|
||||
ret = dce_admin_send_msg(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "Error sending IPC create msg for type [%u]",
|
||||
i);
|
||||
goto out;
|
||||
}
|
||||
|
||||
dce_info(d, "error value : [0x%x]", resp_msg->error);
|
||||
if (resp_msg->error) {
|
||||
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;
|
||||
}
|
||||
|
||||
dce_info(d, "error value : [0x%x]", resp_msg->error);
|
||||
|
||||
if (resp_msg->error) {
|
||||
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;
|
||||
|
||||
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_VERSION");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = dce_admin_send_rm_bootstrap(d, msg);
|
||||
if (ret) {
|
||||
dce_err(d, "RPC failed for DCE_ADMIN_CMD_VERSION");
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
dce_admin_free_message(d, msg);
|
||||
return ret;
|
||||
}
|
||||
602
drivers/platform/tegra/dce/dce-ast.c
Normal file
602
drivers/platform/tegra/dce/dce-ast.c
Normal file
@@ -0,0 +1,602 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#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_info(d, "AST_AST0_CONTROL_R : 0x%x",
|
||||
dce_readl(d, ast_ast0_control_r()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
dce_info(d, "AST_AST1_CONTROL_R : 0x%x",
|
||||
dce_readl(d, ast_ast1_control_r()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_info(d, "AST_AST0_STREAMID_CTL_0_R : 0x%x",
|
||||
dce_readl(d, ast_ast0_streamid_ctl_0_r()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_info(d, "AST_AST0_STREAMID_CTL_1_R : 0x%x",
|
||||
dce_readl(d, ast_ast0_streamid_ctl_1_r()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_info(d, "AST_AST1_STREAMID_CTL_0_R : 0x%x",
|
||||
dce_readl(d, ast_ast1_streamid_ctl_0_r()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
dce_info(d, "AST_AST1_STREAMID_CTL_1_R : 0x%x",
|
||||
dce_readl(d, ast_ast1_streamid_ctl_1_r()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_info(d, "AST_AST0_REGION_0_SLAVE_BASE_LO_R : 0x%x",
|
||||
dce_readl(d, ast_ast0_region_0_slave_base_lo_r()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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());
|
||||
dce_info(d, "AST_AST1_REGION_0_SLAVE_BASE_LO_R : 0x%x",
|
||||
dce_readl(d, ast_ast1_region_0_slave_base_lo_r()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_info(d, "AST_AST0_REGION_0_MASTER_BASE_LO_R : 0x%x",
|
||||
dce_readl(d, ast_ast0_region_0_master_base_lo_r()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_info(d, "AST_AST1_REGION_0_MASTER_BASE_LO_R : 0x%x",
|
||||
dce_readl(d, ast_ast1_region_0_master_base_lo_r()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_info(d, "AST_AST1_REGION_0_MASTER_BASE_HI_R : 0x%x",
|
||||
dce_readl(d, ast_ast1_region_0_master_base_hi_r()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_info(d, "AST_AST0_REGION_0_MASTER_BASE_HI_R : 0x%x",
|
||||
dce_readl(d, ast_ast0_region_0_master_base_hi_r()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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_info(d, "AST_AST0_REGION_0_MASK_LO_R : 0x%x",
|
||||
dce_readl(d, ast_ast0_region_0_mask_lo_r()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
dce_info(d, "AST_AST1_REGION_0_MASK_LO_R : 0x%x",
|
||||
dce_readl(d, ast_ast1_region_0_mask_lo_r()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_info(d, "AST_AST0_REGION_0_CONTROL_R : 0x%x",
|
||||
dce_readl(d, ast_ast0_region_0_control_r()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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());
|
||||
dce_info(d, "AST_AST1_REGION_0_CONTROL_R : 0x%x",
|
||||
dce_readl(d, ast_ast1_region_0_control_r()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
slave_addr = dce_get_fw_dce_addr(d);
|
||||
|
||||
if (!d->fw_data) {
|
||||
dce_err(d, "No fw_data present");
|
||||
return;
|
||||
}
|
||||
|
||||
master_addr = d->fw_data->dma_handle;
|
||||
dce_info(d, "Value of master address 0x%llx\n", master_addr);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
752
drivers/platform/tegra/dce/dce-bootstrap.c
Normal file
752
drivers/platform/tegra/dce/dce-bootstrap.c
Normal file
@@ -0,0 +1,752 @@
|
||||
/*
|
||||
* 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-util-common.h>
|
||||
#include <interface/dce-interface.h>
|
||||
#include <interface/dce-boot-cmds.h>
|
||||
#include <interface/dce-interface.h>
|
||||
|
||||
/**
|
||||
* dce_boot_complete - Checks if dce has complelted boot.
|
||||
*
|
||||
* @d - Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : True if boot is complete
|
||||
*/
|
||||
static inline bool dce_boot_complete(struct tegra_dce *d)
|
||||
{
|
||||
return !!(dce_ss_get_state(d, DCE_BOOT_SEMA)
|
||||
& DCE_BOOT_COMPLETE);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_boot_poll_boot_complete - Poll until dce boot is complete.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
static int dce_boot_poll_boot_complete(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
while (!dce_boot_complete(d)) {
|
||||
dce_worker_thread_wait(d,
|
||||
EVENT_ID_DCE_BOOT_COMPLETE_IRQ_REQ_SET);
|
||||
}
|
||||
|
||||
if (dce_worker_get_state(d) == STATE_DCE_WORKER_ABORTED)
|
||||
ret = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_req_boot_irq_sync - Requests DCE to raise an
|
||||
* interrupt on boot completion.
|
||||
*
|
||||
* @d - Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : 0 if sucessful.
|
||||
*/
|
||||
static int dce_req_boot_irq_sync(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#define DCE_BOOT_INIT_BPOS 31U
|
||||
dce_ss_set(d, DCE_BOOT_INIT_BPOS, DCE_BOOT_SEMA);
|
||||
#undef DCE_BOOT_INIT_BPOS
|
||||
|
||||
dce_info(d, "Waiting on dce fw to boot...");
|
||||
|
||||
ret = dce_boot_poll_boot_complete(d);
|
||||
if (ret)
|
||||
dce_err(d, "DCE Boot Complete Poll Interrupted");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_wait_boot_complete - Wait for the DCE to boot and be ready to receive
|
||||
* commands from CCPLEX driver.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : 0 if successful
|
||||
*/
|
||||
int dce_wait_boot_complete(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (dce_boot_complete(d))
|
||||
goto boot_done;
|
||||
|
||||
ret = dce_req_boot_irq_sync(d);
|
||||
|
||||
boot_done:
|
||||
if (!ret) {
|
||||
dce_set_boot_complete(d, true);
|
||||
dce_info(d, "dce is ready to receive bootstrap commands");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_handle_irq_status - Handles irq status from DCE
|
||||
*
|
||||
* @d : Pointer to struct tegra_dce
|
||||
* @status : Status received from DCE
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
void dce_handle_irq_status(struct tegra_dce *d, u32 status)
|
||||
{
|
||||
enum dce_worker_event_id_type event;
|
||||
|
||||
if (status & DCE_IRQ_LOG_OVERFLOW)
|
||||
dce_info(d, "DCE trace log overflow error received");
|
||||
|
||||
if (status & DCE_IRQ_LOG_READY)
|
||||
dce_info(d, "DCE trace log buffers available");
|
||||
|
||||
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_SC7_ENTERED)
|
||||
dce_info(d, "DCE can be safely powered-off now");
|
||||
|
||||
event = EVENT_ID_DCE_INTERFACE_ERROR_RECEIVED;
|
||||
|
||||
if (status & DCE_IRQ_READY) {
|
||||
dce_info(d, "DCE IRQ Ready Received");
|
||||
event = EVENT_ID_DCE_BOOT_COMPLETE_IRQ_RECEIVED;
|
||||
}
|
||||
|
||||
dce_worker_thread_wakeup(d, event);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* dce_bootstrap_handle_boot_status- Handles boot status from DCE
|
||||
*
|
||||
* @d : Pointer to struct tegra_dce
|
||||
* @status : Status received from DCE
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
void dce_bootstrap_handle_boot_status(struct tegra_dce *d, u32 status)
|
||||
{
|
||||
enum dce_worker_event_id_type event;
|
||||
|
||||
event = EVENT_ID_DCE_IPC_SIGNAL_RECEIVED;
|
||||
|
||||
dce_info(d, "Boot Cmd Resp Received. Status: [%x]", status);
|
||||
|
||||
dce_mailbox_store_interface_status(d, status,
|
||||
DCE_MAILBOX_BOOT_INTERFACE);
|
||||
|
||||
dce_worker_thread_wakeup(d, event);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
enum dce_worker_event_id_type event;
|
||||
|
||||
event = EVENT_ID_DCE_IPC_MESSAGE_SENT;
|
||||
|
||||
dce_worker_thread_wait(d, event);
|
||||
|
||||
status = dce_mailbox_get_interface_status(d,
|
||||
DCE_MAILBOX_BOOT_INTERFACE);
|
||||
|
||||
if (dce_worker_get_state(d) == STATE_DCE_WORKER_ABORTED)
|
||||
return -EINTR;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
dce_err(d, "value of q_struct:");
|
||||
dce_err(d, "ch->q_info.nframes : %u", q_info.nframes);
|
||||
dce_err(d, "ch->q_info.frame_sz: %u", q_info.frame_sz);
|
||||
dce_err(d, "ch->q_info.rx_iova: [0x%llx]", q_info.rx_iova);
|
||||
dce_err(d, "ch->q_info.tx_iova: [0x%llx]", q_info.tx_iova);
|
||||
|
||||
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);
|
||||
dce_info(d, "Frame size received: [%u]", DCE_BOOT_CMD_GET(val));
|
||||
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
dce_info(d, "Version received: [%u]", DCE_BOOT_CMD_GET(val));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_sending:
|
||||
dce_err(d, "Bootstrap process failed");
|
||||
return ret;
|
||||
}
|
||||
259
drivers/platform/tegra/dce/dce-client-ipc.c
Normal file
259
drivers/platform/tegra/dce/dce-client-ipc.c
Normal file
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* 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-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))
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
struct tegra_dce_client_ipc *cl;
|
||||
u32 handle = DCE_CLIENT_IPC_HANDLE_INVALID;
|
||||
|
||||
int_type = dce_interface_type_map[type];
|
||||
|
||||
d = dce_ipc_get_dce_from_ch(int_type);
|
||||
if (d == NULL) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (handlep == NULL) {
|
||||
dce_err(d, "Invalid handle pointer");
|
||||
ret = -EINVAL;
|
||||
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->int_type = int_type;
|
||||
cl->callback_fn = callback_fn;
|
||||
|
||||
d->d_clients[type] = cl;
|
||||
init_completion(&cl->recv_wait);
|
||||
|
||||
out:
|
||||
if (ret != 0) {
|
||||
dce_client_ipc_handle_free(handle);
|
||||
handle = DCE_CLIENT_IPC_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
*handlep = handle;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(tegra_dce_register_ipc_client);
|
||||
|
||||
int tegra_dce_unregister_ipc_client(u32 handle)
|
||||
{
|
||||
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);
|
||||
|
||||
static int dce_client_ipc_wait_rpc(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;
|
||||
}
|
||||
|
||||
wait_for_completion(&cl->recv_wait);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dce_client_ipc_wait(struct tegra_dce *d, u32 w_type, u32 ch_type)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (w_type) {
|
||||
case DCE_IPC_WAIT_TYPE_SYNC:
|
||||
ret = dce_admin_ipc_wait(d, w_type);
|
||||
break;
|
||||
case DCE_IPC_WAIT_TYPE_RPC:
|
||||
ret = dce_client_ipc_wait_rpc(d, ch_type);
|
||||
break;
|
||||
default:
|
||||
dce_err(d, "Invalid wait type [%d]", w_type);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
complete(&cl->recv_wait);
|
||||
}
|
||||
418
drivers/platform/tegra/dce/dce-debug.c
Normal file
418
drivers/platform/tegra/dce/dce-debug.c
Normal file
@@ -0,0 +1,418 @@
|
||||
/*
|
||||
* 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 <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>
|
||||
|
||||
/**
|
||||
* 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_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,
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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_BPMP: 0x%x",
|
||||
dce_smb_read(d, DCE_MBOX_FROM_BPMP));
|
||||
dce_info(d, "DCE_MBOX_TO_BPMP: 0x%x",
|
||||
dce_smb_read(d, DCE_MBOX_TO_BPMP));
|
||||
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);
|
||||
|
||||
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_dce", 0444,
|
||||
d_dev->debugfs, d, &reset_dce_fops);
|
||||
if (!retval)
|
||||
goto err_handle;
|
||||
|
||||
retval = debugfs_create_file("boot_dce", 0444,
|
||||
d_dev->debugfs, d, &boot_dce_fops);
|
||||
if (!retval)
|
||||
goto err_handle;
|
||||
|
||||
retval = debugfs_create_bool("boot_status", 0644,
|
||||
d_dev->debugfs, &d->boot_complete);
|
||||
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;
|
||||
|
||||
return;
|
||||
|
||||
err_handle:
|
||||
dev_err(dev, "could not create debugfs\n");
|
||||
dce_remove_debug(d);
|
||||
}
|
||||
244
drivers/platform/tegra/dce/dce-hsp-smb.c
Normal file
244
drivers/platform/tegra/dce/dce-hsp-smb.c
Normal file
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#define DCE_MAX_NO_SMB 8
|
||||
#define DCE_MAX_HSP_IE 8
|
||||
|
||||
/**
|
||||
* smb_regs is a 1D 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.
|
||||
*/
|
||||
static u32 (*const smb_regs[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 1D 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.
|
||||
*/
|
||||
static u32 (*const smb_full_ie_regs[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 1D 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.
|
||||
*/
|
||||
static u32 (*const smb_empty_ie_regs[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)
|
||||
{
|
||||
if (id >= DCE_MAX_NO_SMB) {
|
||||
dce_err(d, "Invalid Shared Mailbox ID");
|
||||
return;
|
||||
}
|
||||
|
||||
dce_writel(d, smb_regs[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;
|
||||
|
||||
if (id >= DCE_MAX_NO_SMB) {
|
||||
dce_err(d, "Invalid Shared Mailbox ID");
|
||||
return;
|
||||
}
|
||||
|
||||
dce_writel(d, smb_full_ie_regs[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)
|
||||
{
|
||||
if (id >= DCE_MAX_NO_SMB) {
|
||||
dce_err(d, "Invalid Shared Mailbox ID");
|
||||
return 0xffffffff; /* TODO : Add DCE Error Numbers */
|
||||
}
|
||||
|
||||
return dce_readl(d, smb_full_ie_regs[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;
|
||||
|
||||
if (id >= DCE_MAX_NO_SMB) {
|
||||
dce_err(d, "Invalid Shared Mailbox ID");
|
||||
return;
|
||||
}
|
||||
|
||||
dce_writel(d, smb_empty_ie_regs[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)
|
||||
{
|
||||
if (id >= DCE_MAX_NO_SMB) {
|
||||
dce_err(d, "Invalid Shared Mailbox ID : %x", id);
|
||||
return 0xffffffff; /* TODO : Add DCE Error Numbers */
|
||||
}
|
||||
|
||||
return dce_readl(d, smb_regs[id]());
|
||||
}
|
||||
|
||||
/**
|
||||
* hsp_int_ie_regs is a 1D 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.
|
||||
*/
|
||||
static u32 (*const hsp_int_ie_regs[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,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
if (id >= DCE_MAX_HSP_IE) {
|
||||
dce_err(d, "Invalid Shared HSP IE ID");
|
||||
return 0xffffffff; /* TODO : Add DCE Error Numbers */
|
||||
}
|
||||
|
||||
return dce_readl(d, hsp_int_ie_regs[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)
|
||||
{
|
||||
if (id >= DCE_MAX_HSP_IE) {
|
||||
dce_err(d, "Invalid Shared HSP IE ID");
|
||||
return;
|
||||
}
|
||||
|
||||
dce_writel(d, hsp_int_ie_regs[id](),
|
||||
val | dce_readl(d, hsp_int_ie_regs[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)
|
||||
{
|
||||
return dce_readl(d, hsp_int_ir_r());
|
||||
}
|
||||
144
drivers/platform/tegra/dce/dce-hsp-ss.c
Normal file
144
drivers/platform/tegra/dce/dce-hsp-ss.c
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#define DCE_MAX_NO_SS 4
|
||||
|
||||
/**
|
||||
* ss_set_regs is a 1D 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.
|
||||
*/
|
||||
static u32 (*const ss_set_regs[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 1D 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.
|
||||
*/
|
||||
static u32 (*const ss_clear_regs[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 1D 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.
|
||||
*/
|
||||
static u32 (*const ss_state_regs[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)
|
||||
{
|
||||
return dce_readl(d, ss_state_regs[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;
|
||||
|
||||
if (id >= DCE_MAX_NO_SS) {
|
||||
dce_err(d, "Invalid Shared Semaphore 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[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;
|
||||
|
||||
if (id >= DCE_MAX_NO_SS) {
|
||||
dce_err(d, "Invalid Shared Semaphore ID");
|
||||
return;
|
||||
}
|
||||
|
||||
val = dce_ss_get_state(d, id);
|
||||
|
||||
dce_bitmap_set(&val, bpos, 1);
|
||||
|
||||
dce_writel(d, ss_set_regs[id](), val);
|
||||
}
|
||||
76
drivers/platform/tegra/dce/dce-init-deinit.c
Normal file
76
drivers/platform/tegra/dce/dce-init-deinit.c
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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-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;
|
||||
|
||||
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_worker_thread_init(d);
|
||||
if (ret) {
|
||||
dce_err(d, "dce worker thread init failed");
|
||||
goto err_worker_thread_init;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err_worker_thread_init:
|
||||
dce_admin_deinit(d);
|
||||
err_admin_interface_init:
|
||||
dce_boot_interface_deinit(d);
|
||||
err_boot_interface_init:
|
||||
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_worker_thread_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-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-ipc.h>
|
||||
#include <dce-util-common.h>
|
||||
#include <interface/dce-interface.h>
|
||||
|
||||
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;
|
||||
}
|
||||
832
drivers/platform/tegra/dce/dce-ipc.c
Normal file
832
drivers/platform/tegra/dce/dce-ipc.c
Normal file
@@ -0,0 +1,832 @@
|
||||
/*
|
||||
* 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-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>
|
||||
|
||||
struct dce_ipc_channel ivc_channels[DCE_IPC_CH_KMD_TYPE_MAX] = {
|
||||
[DCE_IPC_CH_KMD_TYPE_ADMIN] = {
|
||||
.flags = DCE_IPC_CHANNEL_VALID,
|
||||
.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,
|
||||
.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_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_info(d, "Tot_raw_q_size : [%lu]", tot_q_sz);
|
||||
|
||||
tot_ivc_q_sz = tegra_ivc_total_queue_size(tot_q_sz);
|
||||
|
||||
dce_info(d, "Tot_aligned_q_size : [%lu]", tot_ivc_q_sz);
|
||||
|
||||
region->size = dce_get_nxt_pow_of_2(&tot_ivc_q_sz, 32);
|
||||
|
||||
dce_info(d, "Region size as a power of 2 : [%lu]", region->size);
|
||||
|
||||
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 ivc.
|
||||
*
|
||||
* Do not take a channel lock here.
|
||||
*
|
||||
* Return : Void.
|
||||
*/
|
||||
static void dce_ipc_signal_target(struct ivc *ivc)
|
||||
{
|
||||
struct dce_ipc_channel *ch;
|
||||
|
||||
ch = container_of(ivc, struct dce_ipc_channel, d_ivc);
|
||||
|
||||
ch->signal.notify(ch->d, &ch->signal.to_d);
|
||||
/**
|
||||
* TODO : Get rid of prints
|
||||
*/
|
||||
dce_info(ch->d, "Notify : notify called for [%d]", ch->ch_type);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
dce_mutex_lock(&ch->lock);
|
||||
|
||||
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, w_type, ch_type);
|
||||
|
||||
dce_mutex_lock(&ch->lock);
|
||||
|
||||
ch->w_type = DCE_IPC_WAIT_TYPE_INVALID;
|
||||
|
||||
out:
|
||||
dce_mutex_unlock(&ch->lock);
|
||||
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 (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);
|
||||
dce_mutex_destroy(&ch->lock);
|
||||
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;
|
||||
return ret;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
ret = tegra_ivc_init_with_dma_handle(&ch->d_ivc,
|
||||
(uintptr_t)r->base + r->s_offset,
|
||||
r->iova + r->s_offset,
|
||||
(uintptr_t)r->base + r->s_offset + q_sz,
|
||||
r->iova + r->s_offset + q_sz,
|
||||
q_info->nframes, msg_sz, dev, dce_ipc_signal_target);
|
||||
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;
|
||||
|
||||
|
||||
dce_info(d, "Info for chn_type [%d]", ch_type);
|
||||
dce_info(d, "======================");
|
||||
dce_info(d, "msg_sz [%u]", msg_sz);
|
||||
dce_info(d, "frame_sz [%u]", q_info->frame_sz);
|
||||
dce_info(d, "Max frames [%u]", q_info->nframes);
|
||||
dce_info(d, "q_sz [%u]", q_sz);
|
||||
dce_info(d, "r->s_offset [%u]", r->s_offset);
|
||||
dce_info(d, "base address [0x%p]", r->base);
|
||||
dce_info(d, "q_info->rx_iova [0x%llx]", q_info->rx_iova);
|
||||
dce_info(d, "q_info->tx_iova [0x%llx]", q_info->tx_iova);
|
||||
dce_info(d, "======================");
|
||||
|
||||
trace_ivc_channel_init_complete(d, ch);
|
||||
|
||||
d->d_ipc.ch[ch_type] = ch;
|
||||
r->s_offset += (2 * q_sz);
|
||||
|
||||
dce_mutex_unlock(&ch->lock);
|
||||
|
||||
out_lock_destroy:
|
||||
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 ret;
|
||||
|
||||
struct dce_ipc_channel *ch = d->d_ipc.ch[ch_type];
|
||||
|
||||
dce_mutex_lock(&ch->lock);
|
||||
|
||||
ret = (tegra_ivc_channel_notified(&ch->d_ivc) ? false : true);
|
||||
|
||||
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_channel_reset(&ch->d_ivc);
|
||||
|
||||
dce_info(d, "Channel [%d] sync triggered", ch_type);
|
||||
trace_ivc_channel_reset_triggered(d, ch);
|
||||
|
||||
ch->flags &= ~DCE_IPC_CHANNEL_SYNCED;
|
||||
|
||||
dce_mutex_unlock(&ch->lock);
|
||||
|
||||
dce_ipc_wait(ch->d, DCE_IPC_WAIT_TYPE_SYNC, ch_type);
|
||||
|
||||
dce_mutex_lock(&ch->lock);
|
||||
|
||||
ch->flags |= DCE_IPC_CHANNEL_SYNCED;
|
||||
|
||||
trace_ivc_channel_reset_complete(d, ch);
|
||||
|
||||
dce_info(d, "Channel [%d] : Wait type : [%u]", ch_type, ch->w_type);
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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 ((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);
|
||||
|
||||
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;
|
||||
}
|
||||
/**
|
||||
* TODO : Get rid of prints
|
||||
*/
|
||||
dce_info(d, "Send Message : Retrieved Next Buff to write: [%d]",
|
||||
ch_type);
|
||||
|
||||
ret = _dce_ipc_write_channel(ch, data, size);
|
||||
if (ret) {
|
||||
dce_err(ch->d, "Error writing to channel");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO : Get rid of prints
|
||||
*/
|
||||
dce_info(d, "Send Message : Advanced Channel w_pos: [%d]", ch_type);
|
||||
|
||||
ch->signal.notify(d, &ch->signal.to_d);
|
||||
/**
|
||||
* TODO : Get rid of prints
|
||||
*/
|
||||
dce_info(d, "Send Message : Notified target: [%d]", ch_type);
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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 ((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);
|
||||
|
||||
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_err(ch->d, "Error getting next free buf to read");
|
||||
goto out;
|
||||
}
|
||||
/**
|
||||
* TODO : Get rid of prints
|
||||
*/
|
||||
dce_info(d, "Recv Message : Retrieved Next Buff to read: [%d]",
|
||||
ch_type);
|
||||
|
||||
|
||||
ret = _dce_ipc_read_channel(ch, data, size);
|
||||
if (ret) {
|
||||
dce_err(ch->d, "Error reading from channel");
|
||||
goto out;
|
||||
}
|
||||
/**
|
||||
* TODO : Get rid of prints
|
||||
*/
|
||||
dce_info(d, "Recv Message : Advanced r_pos: [%d]", ch_type);
|
||||
|
||||
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;
|
||||
}
|
||||
/**
|
||||
* TODO : Get rid of prints
|
||||
*/
|
||||
dce_info(d, "%s : Send successful, Waiting for recv: [%d]",
|
||||
__func__, ch_type);
|
||||
|
||||
|
||||
ret = dce_ipc_wait(ch->d, DCE_IPC_WAIT_TYPE_RPC, ch_type);
|
||||
if (ret) {
|
||||
dce_err(ch->d, "Error in waiting for ack");
|
||||
goto done;
|
||||
}
|
||||
/**
|
||||
* TODO : Get rid of prints
|
||||
*/
|
||||
dce_info(d, "%s : Wait complete... Reading Message: [%d]",
|
||||
__func__, ch_type);
|
||||
|
||||
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;
|
||||
}
|
||||
/**
|
||||
* TODO : Get rid of prints
|
||||
*/
|
||||
dce_info(d, "Send Message Sync: Read Sucessful: [%d]", ch_type);
|
||||
|
||||
|
||||
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;
|
||||
struct dce_ipc_channel *ch = d->d_ipc.ch[ch_type];
|
||||
|
||||
dce_mutex_lock(&ch->lock);
|
||||
|
||||
if (tegra_ivc_can_read(&ch->d_ivc))
|
||||
ret = true;
|
||||
|
||||
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;
|
||||
}
|
||||
272
drivers/platform/tegra/dce/dce-mailbox.c
Normal file
272
drivers/platform/tegra/dce/dce-mailbox.c
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* 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-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);
|
||||
|
||||
dce_info(d, "Mailbox INTR Rcvd. IRQ SOURCES = [%x]", irq_sources);
|
||||
|
||||
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_mailbox_store_interface_status(d, value, i);
|
||||
d_mb->notify(d, d_mb->notify_data);
|
||||
dce_smb_set(d, 0U, d_mb->r_mb);
|
||||
}
|
||||
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, "Warning : 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_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_interface *d_mb;
|
||||
|
||||
dce_info(d, "write cmd received for interface : %d", interface);
|
||||
|
||||
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_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);
|
||||
}
|
||||
257
drivers/platform/tegra/dce/dce-module.c
Normal file
257
drivers/platform/tegra/dce/dce-module.c
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* 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 <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>
|
||||
|
||||
static const struct dce_platform_data t234_dce_platform_data = {
|
||||
.dce_stream_id = 0x05,
|
||||
.phys_stream_id = 0x7f,
|
||||
.fw_carveout_id = 9,
|
||||
.fw_vmindex = 0,
|
||||
.fw_name = "dce.bin",
|
||||
.fw_dce_addr = 0x40000000,
|
||||
.fw_info_valid = true,
|
||||
.use_physical_id = false,
|
||||
};
|
||||
|
||||
static const struct of_device_id tegra_dce_of_match[] = {
|
||||
{
|
||||
.compatible = "nvidia,tegra234-dce",
|
||||
.data = (struct dce_platform_data *)&t234_dce_platform_data
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_set_pdata_dce - inline function to set the tegra_dce pointer in
|
||||
* pdata point to actual tegra_dce data structure.
|
||||
*
|
||||
* @pdev : Pointer to the platform device data structure.
|
||||
* @d : Pointer pointing to actual tegra_dce data structure.
|
||||
*
|
||||
* Return : Void.
|
||||
*/
|
||||
static inline void dce_set_pdata_dce(struct platform_device *pdev,
|
||||
struct tegra_dce *d)
|
||||
{
|
||||
((struct dce_platform_data *)dev_get_drvdata(&pdev->dev))->d = d;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_get_pdata_dce - inline function to get the tegra_dce pointer
|
||||
* from platform devicve.
|
||||
*
|
||||
* @pdev : Pointer to the platform device data structure.
|
||||
* @d : Pointer pointing to actual tegra_dce data structure.
|
||||
*
|
||||
* Return : Void.
|
||||
*/
|
||||
static inline struct tegra_dce *dce_get_pdata_dce(struct platform_device *pdev)
|
||||
{
|
||||
return (((struct dce_platform_data *)dev_get_drvdata(&pdev->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 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;
|
||||
|
||||
dce_set_pdata_dce(pdev, &d_dev->d);
|
||||
d_dev->dev = dev;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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_platform_data *pdata = NULL;
|
||||
|
||||
pdata = dev_get_drvdata(&pdev->dev);
|
||||
d = pdata->d;
|
||||
|
||||
for (i = 0; i < pdata->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_platform_data *pdata = NULL;
|
||||
|
||||
pdata = dev_get_drvdata(&pdev->dev);
|
||||
d = pdata->d;
|
||||
no_ints = of_irq_count(pdev->dev.of_node);
|
||||
if (no_ints == 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"Invalid number of interrupts configured = %d",
|
||||
no_ints);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pdata->max_cpu_irqs = no_ints;
|
||||
|
||||
for (i = 0; i < no_ints; i++) {
|
||||
ret = of_irq_get(pdev->dev.of_node, 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 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;
|
||||
|
||||
match = of_match_device(tegra_dce_of_match, dev);
|
||||
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;
|
||||
}
|
||||
dev_set_drvdata(dev, pdata);
|
||||
|
||||
err = dce_init_dev_data(pdev);
|
||||
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 = pdata->d;
|
||||
|
||||
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
|
||||
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);
|
||||
dce_set_irqs(pdev, false);
|
||||
dce_driver_deinit(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver tegra_dce_driver = {
|
||||
.driver = {
|
||||
.name = "tegra-dce",
|
||||
.of_match_table =
|
||||
of_match_ptr(tegra_dce_of_match),
|
||||
},
|
||||
.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");
|
||||
84
drivers/platform/tegra/dce/dce-reset.c
Normal file
84
drivers/platform/tegra/dce/dce-reset.c
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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_info(d, "EVP_RESET_ADDR_R : 0x%x",
|
||||
dce_readl(d, evp_reset_addr_r()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_info(d, "PM_R5_CTRL_R : 0x%x", dce_readl(d, pm_r5_ctrl_r()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
600
drivers/platform/tegra/dce/dce-util-common.c
Normal file
600
drivers/platform/tegra/dce/dce-util-common.c
Normal file
@@ -0,0 +1,600 @@
|
||||
/*
|
||||
* 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-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;
|
||||
u32 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;
|
||||
|
||||
request_firmware(&l_fw, fw_name, dev);
|
||||
|
||||
if (!l_fw)
|
||||
goto err;
|
||||
|
||||
/* Make sure the address is aligned to 4K */
|
||||
fw->size = l_fw->size;
|
||||
dce_info(d, "Size of l_fw is %lu\n", 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;
|
||||
dce_info(d, "Size of fw after alignment is %lu\n", fw->size);
|
||||
|
||||
fw->data = dma_alloc_coherent(dev, fw->size,
|
||||
(dma_addr_t *)&fw->dma_handle,
|
||||
GFP_KERNEL);
|
||||
if (!fw->data)
|
||||
goto err_release;
|
||||
|
||||
dce_info(d, "Value of dma_address 0x%llx\n", fw->dma_handle);
|
||||
|
||||
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)->dce_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_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);
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
318
drivers/platform/tegra/dce/dce-worker.c
Normal file
318
drivers/platform/tegra/dce/dce-worker.c
Normal file
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
* 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-cond.h>
|
||||
#include <dce-lock.h>
|
||||
#include <dce-worker.h>
|
||||
#include <dce-util-common.h>
|
||||
#include <interface/dce-admin-cmds.h>
|
||||
|
||||
/**
|
||||
* dce_worker_wakeup_cond - Generic wake up condition for
|
||||
* dce_worker thread.
|
||||
*
|
||||
* @d : Pointer to struct tegra_dce.
|
||||
*
|
||||
* Return : Boolean
|
||||
*/
|
||||
static bool dce_worker_wakeup_cond(struct tegra_dce *d)
|
||||
{
|
||||
struct dce_worker_info *w = &d->wrk_info;
|
||||
|
||||
return (w->state_changed == true ||
|
||||
dce_thread_should_stop(&w->wrk_thread));
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_worker_thread_wait - Will wait in a given state.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @event : Event that will trigger the wait.
|
||||
*
|
||||
* Will change state and wait based on the event that
|
||||
* triggers the wait.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
void dce_worker_thread_wait(struct tegra_dce *d,
|
||||
enum dce_worker_event_id_type event)
|
||||
{
|
||||
int ret;
|
||||
u32 timeout_val_ms = 0;
|
||||
enum dce_worker_state new_state;
|
||||
struct dce_worker_info *w = &d->wrk_info;
|
||||
|
||||
if (w->state_changed == true) {
|
||||
dce_warn(d, "Unexpected state_changed value");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case EVENT_ID_DCE_BOOT_COMPLETE_IRQ_REQ_SET:
|
||||
if ((w->c_state != STATE_DCE_WORKER_IDLE) &&
|
||||
(w->c_state != STATE_DCE_WORKER_BOOT_WAIT)) {
|
||||
dce_warn(d, "Unexpected wait event [%d] rcvd in state [%d]",
|
||||
event, w->c_state);
|
||||
return;
|
||||
}
|
||||
new_state = STATE_DCE_WORKER_BOOT_WAIT;
|
||||
break;
|
||||
case EVENT_ID_DCE_IPC_SYNC_TRIGGERED:
|
||||
case EVENT_ID_DCE_IPC_MESSAGE_SENT:
|
||||
new_state = STATE_DCE_WORKER_WFI;
|
||||
break;
|
||||
case EVENT_ID_DCE_BOOT_COMPLETE:
|
||||
new_state = STATE_DCE_WORKER_IDLE;
|
||||
break;
|
||||
default:
|
||||
dce_warn(d, "Invalid wait event [%d] rcvd in state [%d]",
|
||||
event, w->c_state);
|
||||
return;
|
||||
}
|
||||
|
||||
dce_mutex_lock(&w->lock);
|
||||
w->c_state = new_state;
|
||||
dce_mutex_unlock(&w->lock);
|
||||
|
||||
if (new_state == STATE_DCE_WORKER_BOOT_WAIT)
|
||||
timeout_val_ms = 1000;
|
||||
|
||||
ret = DCE_COND_WAIT_INTERRUPTIBLE(&w->cond,
|
||||
dce_worker_wakeup_cond(d),
|
||||
timeout_val_ms);
|
||||
if (ret)
|
||||
dce_info(d, "Timeout occurred in event [%d] & state [%d]",
|
||||
event, w->c_state);
|
||||
|
||||
dce_mutex_lock(&w->lock);
|
||||
|
||||
w->state_changed = false;
|
||||
|
||||
if (ret)
|
||||
w->c_state = STATE_DCE_WORKER_IDLE;
|
||||
|
||||
dce_mutex_unlock(&w->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_worker_thread_wakeup - Wakeup the dce worker thread
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
* @event : Event that will trigger the wakeup.
|
||||
*
|
||||
* Will change state and wakeup the worker thread based on
|
||||
* the event that triggers it.
|
||||
*
|
||||
* Return : Void
|
||||
*/
|
||||
void dce_worker_thread_wakeup(struct tegra_dce *d,
|
||||
enum dce_worker_event_id_type event)
|
||||
{
|
||||
struct dce_worker_info *w = &d->wrk_info;
|
||||
enum dce_worker_state new_state = w->c_state;
|
||||
|
||||
if (w->state_changed == true) {
|
||||
dce_warn(d, "Unexpected state_changed value");
|
||||
dce_mutex_unlock(&w->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case EVENT_ID_DCE_IPC_SIGNAL_RECEIVED:
|
||||
if (w->c_state != STATE_DCE_WORKER_WFI) {
|
||||
dce_warn(d, "Unexpected wakeup event rcvd: [%d]. Cur State: [%d]",
|
||||
event, w->c_state);
|
||||
return;
|
||||
}
|
||||
new_state = STATE_DCE_WORKER_IDLE;
|
||||
break;
|
||||
case EVENT_ID_DCE_BOOT_COMPLETE_IRQ_RECEIVED:
|
||||
if (w->c_state != STATE_DCE_WORKER_BOOT_WAIT) {
|
||||
dce_warn(d, "Unexpected wakeup event rcvd: [%d]. Cur State: [%d]",
|
||||
event, w->c_state);
|
||||
return;
|
||||
}
|
||||
new_state = STATE_DCE_WORKER_IDLE;
|
||||
break;
|
||||
case EVENT_ID_DCE_INTERFACE_ERROR_RECEIVED:
|
||||
new_state = STATE_DCE_WORKER_HANDLE_DCE_ERROR;
|
||||
dce_warn(d, "Error Event Rcvd: [%d]. Cur State: [%d]",
|
||||
event, w->c_state);
|
||||
break;
|
||||
case EVENT_ID_DCE_THREAD_ABORT_REQ_RECEIVED:
|
||||
if (dce_thread_should_stop(&w->wrk_thread))
|
||||
new_state = STATE_DCE_WORKER_ABORTED;
|
||||
else
|
||||
dce_warn(d, "Unexpected wakeup event rcvd: [%d]. Cur State: [%d]",
|
||||
event, w->c_state);
|
||||
break;
|
||||
default:
|
||||
dce_warn(d, "Unexpected wakeup event rcvd: [%d]. Cur State: [%d]",
|
||||
event, w->c_state);
|
||||
return;
|
||||
}
|
||||
|
||||
dce_mutex_lock(&w->lock);
|
||||
w->c_state = new_state;
|
||||
w->state_changed = true;
|
||||
dce_mutex_unlock(&w->lock);
|
||||
|
||||
dce_cond_signal_interruptible(&w->cond);
|
||||
}
|
||||
|
||||
static void dce_handle_dce_error(struct tegra_dce *d)
|
||||
{
|
||||
/**
|
||||
* TODO : Handle error messages from DCE
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* dce_worker - dce worker main function to manage dce thread states.
|
||||
*
|
||||
* @arg : Void pointer to be typecast to tegra_dce struct before use.
|
||||
*
|
||||
* Return : 0 on success.
|
||||
*/
|
||||
static int dce_worker(void *arg)
|
||||
{
|
||||
int ret = 0;
|
||||
struct tegra_dce *d = (struct tegra_dce *)arg;
|
||||
struct dce_worker_info *w = &d->wrk_info;
|
||||
|
||||
dce_info(d, "Starting DCE Worker Thread...");
|
||||
ret = dce_wait_boot_complete(d);
|
||||
if (ret) {
|
||||
dce_warn(d, "DCE Boot didn't complete");
|
||||
goto worker_exit;
|
||||
}
|
||||
|
||||
dce_info(d, "DCE Ready to bootstrap ...");
|
||||
|
||||
ret = dce_start_bootstrap_flow(d);
|
||||
if (ret) {
|
||||
dce_warn(d, "DCE Bootstrap flow didn't complete");
|
||||
goto worker_exit;
|
||||
}
|
||||
|
||||
dce_info(d, "DCE Bootstrapping Complete...");
|
||||
|
||||
dce_admin_ivc_channel_reset(d);
|
||||
|
||||
dce_info(d, "DCE Admin Channel Reset Complete...");
|
||||
|
||||
ret = dce_start_admin_seq(d);
|
||||
if (ret)
|
||||
dce_warn(d, "DCE Admin flow didn't complete");
|
||||
|
||||
dce_worker_thread_wait(d, EVENT_ID_DCE_BOOT_COMPLETE);
|
||||
|
||||
while ((w->c_state != STATE_DCE_WORKER_ABORTED) ||
|
||||
(!dce_thread_should_stop(&w->wrk_thread))) {
|
||||
if (w->c_state == STATE_DCE_WORKER_HANDLE_DCE_ERROR)
|
||||
dce_handle_dce_error(d);
|
||||
}
|
||||
|
||||
worker_exit:
|
||||
if (w->c_state == STATE_DCE_WORKER_ABORTED)
|
||||
dce_info(d, "Exiting Dce Worker Thread");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_worker_get_state - Gets the current state of dce_worker
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct
|
||||
*
|
||||
* Return : Current state
|
||||
*/
|
||||
enum dce_worker_state dce_worker_get_state(struct tegra_dce *d)
|
||||
{
|
||||
return d->wrk_info.c_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_worker_thread_init - Initializes the worker thread and
|
||||
* its corresponding resources.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return : 0 if success.
|
||||
*/
|
||||
int dce_worker_thread_init(struct tegra_dce *d)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dce_worker_info *w
|
||||
= &d->wrk_info;
|
||||
|
||||
ret = dce_cond_init(&w->cond);
|
||||
if (ret) {
|
||||
dce_err(d, "dce condition initialization failed for worker");
|
||||
goto err_cond_init;
|
||||
}
|
||||
|
||||
ret = dce_mutex_init(&w->lock);
|
||||
if (ret) {
|
||||
dce_err(d, "dce condition initialization failed for worker");
|
||||
goto err_lock_init;
|
||||
}
|
||||
|
||||
dce_mutex_lock(&w->lock);
|
||||
|
||||
w->state_changed = false;
|
||||
|
||||
w->c_state = STATE_DCE_WORKER_IDLE;
|
||||
|
||||
ret = dce_thread_create(&w->wrk_thread, d,
|
||||
dce_worker, "dce_worker_thread");
|
||||
if (ret) {
|
||||
dce_err(d, "Dce Worker Thread creation failed");
|
||||
dce_mutex_unlock(&w->lock);
|
||||
goto err_thread_create;
|
||||
}
|
||||
|
||||
dce_mutex_unlock(&w->lock);
|
||||
|
||||
return ret;
|
||||
|
||||
err_thread_create:
|
||||
dce_mutex_destroy(&w->lock);
|
||||
err_lock_init:
|
||||
dce_cond_destroy(&w->cond);
|
||||
err_cond_init:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dce_worker_thread_deinit - Kill the dce worker thread and
|
||||
* its corresponding resources.
|
||||
*
|
||||
* @d : Pointer to tegra_dce struct.
|
||||
*
|
||||
* Return :Void
|
||||
*/
|
||||
void dce_worker_thread_deinit(struct tegra_dce *d)
|
||||
{
|
||||
struct dce_worker_info *w = &d->wrk_info;
|
||||
|
||||
if (dce_thread_is_running(&w->wrk_thread))
|
||||
dce_thread_stop(&w->wrk_thread);
|
||||
|
||||
dce_thread_join(&w->wrk_thread);
|
||||
|
||||
dce_mutex_destroy(&w->lock);
|
||||
|
||||
dce_cond_destroy(&w->cond);
|
||||
}
|
||||
34
drivers/platform/tegra/dce/include/dce-client-ipc-internal.h
Normal file
34
drivers/platform/tegra/dce/include/dce-client-ipc-internal.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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_CLIENT_IPC_INTERNAL_H
|
||||
#define DCE_CLIENT_IPC_INTERNAL_H
|
||||
|
||||
#include <linux/platform/tegra/dce/dce-client-ipc.h>
|
||||
|
||||
struct tegra_dce_client_ipc {
|
||||
bool valid;
|
||||
void *data;
|
||||
uint32_t type;
|
||||
uint32_t int_type;
|
||||
struct tegra_dce *d;
|
||||
struct dce_ivc_channel *ch;
|
||||
struct completion recv_wait;
|
||||
tegra_dce_client_ipc_callback_t callback_fn;
|
||||
};
|
||||
|
||||
void dce_client_ipc_wakeup(struct tegra_dce *d, u32 ch_type);
|
||||
|
||||
int dce_client_ipc_wait(struct tegra_dce *d, u32 w_type, u32 ch_type);
|
||||
|
||||
#endif
|
||||
102
drivers/platform/tegra/dce/include/dce-cond.h
Normal file
102
drivers/platform/tegra/dce/include/dce-cond.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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_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
|
||||
* @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(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 - 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(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-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
|
||||
188
drivers/platform/tegra/dce/include/dce-ipc.h
Normal file
188
drivers/platform/tegra/dce/include/dce-ipc.h
Normal file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* 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_IPC_H
|
||||
#define DCE_IPC_H
|
||||
|
||||
#include <dce-lock.h>
|
||||
#include <linux/tegra-ivc-instance.h>
|
||||
#include <linux/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 2U
|
||||
|
||||
/**
|
||||
* 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_ADMIN_CMD_MAX_FSIZE 1024U
|
||||
|
||||
#define DCE_IPC_WAIT_TYPE_INVALID 0U
|
||||
#define DCE_IPC_WAIT_TYPE_SYNC 1U
|
||||
#define DCE_IPC_WAIT_TYPE_RPC 2U
|
||||
|
||||
#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_MAX 3U
|
||||
/**
|
||||
* 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 __iomem *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;
|
||||
void *ibuff;
|
||||
void *obuff;
|
||||
struct 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);
|
||||
|
||||
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
|
||||
69
drivers/platform/tegra/dce/include/dce-log.h
Normal file
69
drivers/platform/tegra/dce/include/dce-log.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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_LOG_H
|
||||
#define DCE_LOG_H
|
||||
|
||||
struct tegra_dce;
|
||||
|
||||
enum dce_log_type {
|
||||
DCE_ERROR,
|
||||
DCE_WARNING,
|
||||
DCE_INFO,
|
||||
};
|
||||
|
||||
/*
|
||||
* 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)
|
||||
|
||||
#endif
|
||||
66
drivers/platform/tegra/dce/include/dce-mailbox.h
Normal file
66
drivers/platform/tegra/dce/include/dce-mailbox.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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_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_MAX_INTERFACES 3U
|
||||
|
||||
/**
|
||||
* 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_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
|
||||
23
drivers/platform/tegra/dce/include/dce-regs.h
Normal file
23
drivers/platform/tegra/dce/include/dce-regs.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#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
|
||||
63
drivers/platform/tegra/dce/include/dce-util-common.h
Normal file
63
drivers/platform/tegra/dce/include/dce-util-common.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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_UTIL_COMMON_H
|
||||
#define DCE_UTIL_COMMON_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/bitmap.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
|
||||
81
drivers/platform/tegra/dce/include/dce-worker.h
Normal file
81
drivers/platform/tegra/dce/include/dce-worker.h
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.
|
||||
*/
|
||||
|
||||
#ifndef DCE_WORKER_H
|
||||
#define DCE_WORKER_H
|
||||
|
||||
#include <dce-cond.h>
|
||||
#include <dce-lock.h>
|
||||
#include <dce-thread.h>
|
||||
|
||||
struct tegra_dce;
|
||||
|
||||
/**
|
||||
* enum dce_worker_event_id_type - IDs to be used to convey various
|
||||
* events thoughout the life cycle of dce worker thread.
|
||||
*/
|
||||
enum dce_worker_event_id_type {
|
||||
EVENT_ID_DCE_BOOT_COMPLETE_IRQ_REQ_SET = 0,
|
||||
EVENT_ID_DCE_BOOT_COMPLETE_IRQ_RECEIVED = 1,
|
||||
EVENT_ID_DCE_IPC_SYNC_TRIGGERED = 2,
|
||||
EVENT_ID_DCE_IPC_MESSAGE_SENT = 3,
|
||||
EVENT_ID_DCE_IPC_SIGNAL_RECEIVED = 4,
|
||||
EVENT_ID_DCE_THREAD_ABORT_REQ_RECEIVED = 5,
|
||||
EVENT_ID_DCE_INTERFACE_ERROR_RECEIVED = 6,
|
||||
EVENT_ID_DCE_BOOT_COMPLETE = 7,
|
||||
};
|
||||
|
||||
/**
|
||||
* dce_worker_state - Different states of dce worker thread.
|
||||
*/
|
||||
enum dce_worker_state {
|
||||
STATE_DCE_WORKER_IDLE = 0,
|
||||
STATE_DCE_WORKER_BOOT_WAIT = 1,
|
||||
STATE_DCE_WORKER_WFI = 2,
|
||||
STATE_DCE_WORKER_ABORTED = 3,
|
||||
STATE_DCE_WORKER_HANDLE_DCE_ERROR = 4,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dce_worker_info - Contains information to control and manage
|
||||
* dce worker thread throughout its lifecycle.
|
||||
* @wrk_thread : Event driven dce thread to manage initilaization and
|
||||
* release workflow.
|
||||
* @state_changed : Boolean to convey state changes.
|
||||
* @c_state : Stores the current state of dce worker thread. State changes
|
||||
* are triggered by vrious events.
|
||||
* @lock : Used for exclusive state modifications from thread and
|
||||
* interrupt context.
|
||||
* @cond : dce_cond to manage various thread states.
|
||||
*/
|
||||
struct dce_worker_info {
|
||||
struct dce_thread wrk_thread;
|
||||
bool state_changed;
|
||||
enum dce_worker_state c_state;
|
||||
struct dce_mutex lock;
|
||||
struct dce_cond cond;
|
||||
};
|
||||
|
||||
void dce_worker_thread_wait(struct tegra_dce *d,
|
||||
enum dce_worker_event_id_type event);
|
||||
|
||||
void dce_worker_thread_wakeup(struct tegra_dce *d,
|
||||
enum dce_worker_event_id_type event);
|
||||
|
||||
enum dce_worker_state dce_worker_get_state(struct tegra_dce *d);
|
||||
|
||||
int dce_worker_thread_init(struct tegra_dce *d);
|
||||
|
||||
void dce_worker_thread_deinit(struct tegra_dce *d);
|
||||
|
||||
#endif
|
||||
325
drivers/platform/tegra/dce/include/dce.h
Normal file
325
drivers/platform/tegra/dce/include/dce.h
Normal file
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* 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_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-mailbox.h>
|
||||
#include <dce-client-ipc-internal.h>
|
||||
|
||||
#define DCE_MAX_CPU_IRQS 4
|
||||
|
||||
struct tegra_dce;
|
||||
|
||||
/**
|
||||
* struct dce_platform_data - Data Structure to hold platform specific DCE
|
||||
* cluster data.
|
||||
*/
|
||||
struct dce_platform_data {
|
||||
/**
|
||||
* @d : Pointer to OS agnostic dce struct. Stores all runitme info
|
||||
* for dce cluster elements.
|
||||
*/
|
||||
struct tegra_dce *d;
|
||||
/**
|
||||
* @max_cpu_irqs : stores maximum no. os irqs from DCE cluster to CPU
|
||||
* for this platform.
|
||||
*/
|
||||
u8 max_cpu_irqs;
|
||||
/**
|
||||
* @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;
|
||||
/**
|
||||
* dce_stream_id : DCE stream ID to program the ASTs in debug mode
|
||||
* only.
|
||||
*/
|
||||
u32 dce_stream_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];
|
||||
/**
|
||||
* @wrk_info - Data Structure to manage dce worker thread states.
|
||||
*/
|
||||
struct dce_worker_info wrk_info;
|
||||
/**
|
||||
* @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];
|
||||
/**
|
||||
* @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;
|
||||
/**
|
||||
* @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;
|
||||
#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 dev_get_drvdata(dev_from_dce(d));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_wait_boot_complete(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_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_ipc_wait(struct tegra_dce *d, u32 w_type);
|
||||
void dce_admin_ipc_handle_signal(struct tegra_dce *d, u32 ch_type);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
void dce_init_debug(struct tegra_dce *d);
|
||||
#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
|
||||
156
drivers/platform/tegra/dce/include/interface/dce-admin-cmds.h
Normal file
156
drivers/platform/tegra/dce/include/interface/dce-admin-cmds.h
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* NVIDIA Corporation and its licensors retain all intellectual property
|
||||
* and proprietary rights in and to this software, related documentation
|
||||
* and any modifications thereto. Any use, reproduction, disclosure or
|
||||
* distribution of this software and related documentation without an express
|
||||
* license agreement from NVIDIA Corporation is strictly prohibited.
|
||||
*/
|
||||
|
||||
#ifndef DCE_ADMIN_CMDS_H
|
||||
#define DCE_ADMIN_CMDS_H
|
||||
|
||||
#include <interface/dce-types.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 2
|
||||
|
||||
#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 0x02U // echo data back to CCPLEX
|
||||
#define DCE_ADMIN_CMD_MEM_MAP 0x03U // map a region of memory
|
||||
#define DCE_ADMIN_CMD_MEM_INFO 0x04U // return info about a region
|
||||
#define DCE_ADMIN_CMD_IPC_INFO 0x05U // return IPC chan info
|
||||
#define DCE_ADMIN_CMD_IPC_CREATE 0x06U // create an IPC channel
|
||||
#define DCE_ADMIN_CMD_PREPARE_SC7 0x07U // prepare to enter SC7
|
||||
#define DCE_ADMIN_CMD_ENTER_SC7 0x08U // enter SC7
|
||||
#define DCE_ADMIN_CMD_SET_LOGGING 0x09U // set logging level
|
||||
#define DCE_ADMIN_CMD_GET_LOG_INFO 0x08U // get current log info
|
||||
#define DCE_ADMIN_CMD_LOCK_CHANGES 0x0AU // lock creating new channels
|
||||
// and changing memory areas
|
||||
#define DCE_ADMIN_CMD_CODE_COVERAGE_START 0x0BU // start collecting code
|
||||
// coverage data
|
||||
#define DCE_ADMIN_CMD_CODE_COVERAGE_STOP 0x0CU // stop collecting code
|
||||
// coverage data
|
||||
#define DCE_ADMIN_CMD_PERF_START 0x0DU // start collecting perf data
|
||||
#define DCE_ADMIN_CMD_PERF_STOP 0x0EU // stop collecting perf data
|
||||
#define DCE_ADMIN_CMD_TEST_START 0x0FU // start tests
|
||||
#define DCE_ADMIN_CMD_TEST_STOP 0x10U // stop tests and return status
|
||||
#define DCE_ADMIN_CMD_DEBUG 0x11U // debug command
|
||||
|
||||
#define DCE_ADMIN_CMD_RM_BOOTSTRAP 0x12U // tell RM to "bootstrap"
|
||||
|
||||
#define DCE_ADMIN_CMD_NEXT 0x13U // 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;
|
||||
};
|
||||
|
||||
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_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;
|
||||
} 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;
|
||||
} args;
|
||||
};
|
||||
|
||||
#endif
|
||||
27
drivers/platform/tegra/dce/include/interface/dce-bitops.h
Normal file
27
drivers/platform/tegra/dce/include/interface/dce-bitops.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* NVIDIA Corporation and its licensors retain all intellectual property
|
||||
* and proprietary rights in and to this software, related documentation
|
||||
* and any modifications thereto. Any use, reproduction, disclosure or
|
||||
* distribution of this software and related documentation without an express
|
||||
* license agreement from NVIDIA Corporation is strictly prohibited.
|
||||
*/
|
||||
|
||||
#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
|
||||
111
drivers/platform/tegra/dce/include/interface/dce-boot-cmds.h
Normal file
111
drivers/platform/tegra/dce/include/interface/dce-boot-cmds.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* NVIDIA Corporation and its licensors retain all intellectual property
|
||||
* and proprietary rights in and to this software, related documentation
|
||||
* and any modifications thereto. Any use, reproduction, disclosure or
|
||||
* distribution of this software and related documentation without an express
|
||||
* license agreement from NVIDIA Corporation is strictly prohibited.
|
||||
*/
|
||||
|
||||
#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,34 @@
|
||||
/*
|
||||
* Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* NVIDIA Corporation and its licensors retain all intellectual property
|
||||
* and proprietary rights in and to this software, related documentation
|
||||
* and any modifications thereto. Any use, reproduction, disclosure or
|
||||
* distribution of this software and related documentation without an express
|
||||
* license agreement from NVIDIA Corporation is strictly prohibited.
|
||||
*/
|
||||
|
||||
#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,25 @@
|
||||
/*
|
||||
* Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* NVIDIA Corporation and its licensors retain all intellectual property
|
||||
* and proprietary rights in and to this software, related documentation
|
||||
* and any modifications thereto. Any use, reproduction, disclosure or
|
||||
* distribution of this software and related documentation without an express
|
||||
* license agreement from NVIDIA Corporation is strictly prohibited.
|
||||
*/
|
||||
|
||||
#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
|
||||
112
drivers/platform/tegra/dce/include/interface/dce-interface.h
Normal file
112
drivers/platform/tegra/dce/include/interface/dce-interface.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* NVIDIA Corporation and its licensors retain all intellectual property
|
||||
* and proprietary rights in and to this software, related documentation
|
||||
* and any modifications thereto. Any use, reproduction, disclosure or
|
||||
* distribution of this software and related documentation without an express
|
||||
* license agreement from NVIDIA Corporation is strictly prohibited.
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
/*
|
||||
* 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_BPMP (hsp_mbox_t)2U // signal from BPMP IPC
|
||||
#define DCE_MBOX_TO_BPMP (hsp_mbox_t)3U // signal to BPMP 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,18 @@
|
||||
/*
|
||||
* Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* NVIDIA Corporation and its licensors retain all intellectual property
|
||||
* and proprietary rights in and to this software, related documentation
|
||||
* and any modifications thereto. Any use, reproduction, disclosure or
|
||||
* distribution of this software and related documentation without an express
|
||||
* license agreement from NVIDIA Corporation is strictly prohibited.
|
||||
*/
|
||||
|
||||
#ifndef DCE_IPC_HEADER_H
|
||||
#define DCE_IPC_HEADER_H
|
||||
|
||||
struct dce_ipc_header {
|
||||
uint32_t length;
|
||||
};
|
||||
|
||||
#endif
|
||||
36
drivers/platform/tegra/dce/include/interface/dce-ipc-state.h
Normal file
36
drivers/platform/tegra/dce/include/interface/dce-ipc-state.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* NVIDIA Corporation and its licensors retain all intellectual property
|
||||
* and proprietary rights in and to this software, related documentation
|
||||
* and any modifications thereto. Any use, reproduction, disclosure or
|
||||
* distribution of this software and related documentation without an express
|
||||
* license agreement from NVIDIA Corporation is strictly prohibited.
|
||||
*/
|
||||
|
||||
#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,31 @@
|
||||
/*
|
||||
* Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* NVIDIA Corporation and its licensors retain all intellectual property
|
||||
* and proprietary rights in and to this software, related documentation
|
||||
* and any modifications thereto. Any use, reproduction, disclosure or
|
||||
* distribution of this software and related documentation without an express
|
||||
* license agreement from NVIDIA Corporation is strictly prohibited.
|
||||
*/
|
||||
|
||||
#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
|
||||
16
drivers/platform/tegra/dce/include/interface/dce-types.h
Normal file
16
drivers/platform/tegra/dce/include/interface/dce-types.h
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* NVIDIA Corporation and its licensors retain all intellectual property
|
||||
* and proprietary rights in and to this software, related documentation
|
||||
* and any modifications thereto. Any use, reproduction, disclosure or
|
||||
* distribution of this software and related documentation without an express
|
||||
* license agreement from NVIDIA Corporation is strictly prohibited.
|
||||
*/
|
||||
|
||||
#ifndef DCE_TYPES_H
|
||||
#define DCE_TYPES_H
|
||||
|
||||
typedef uint64_t dce_iova;
|
||||
|
||||
#endif
|
||||
83
include/linux/platform/tegra/dce/dce-client-ipc.h
Normal file
83
include/linux/platform/tegra/dce/dce-client-ipc.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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_MAX 2U
|
||||
|
||||
/**
|
||||
* 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
|
||||
98
include/trace/events/dce_events.h
Normal file
98
include/trace/events/dce_events.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* include/trace/events/dce_events.h
|
||||
*
|
||||
* Display event logging to ftrace.
|
||||
*
|
||||
* Copyright (c) 2020-, 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.w_pos, __entry->ch->d_ivc.r_pos,
|
||||
__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