diff --git a/drivers/video/tegra/host/pva/fw_config_t264.h b/drivers/video/tegra/host/pva/fw_config_t264.h new file mode 100644 index 00000000..e105371c --- /dev/null +++ b/drivers/video/tegra/host/pva/fw_config_t264.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; If not, see . + */ + +#ifndef FW_CONFIG_T264_H +#define FW_CONFIG_T264_H +/** + * @brief Total number of AXI data buffers for T26x. + */ +#define PVA_NUM_DMA_ADB_BUFFS_T26X 304U + +/** + * @brief Number of reserved AXI data buffers for T26x. + */ +#define PVA_NUM_RESERVED_ADB_BUFFERS_T26X 16U + +/** + * @brief Number of dynamic AXI data buffers for T26x. + * These exclude the reserved AXI data buffers from total available ones. + */ +#define PVA_NUM_DYNAMIC_ADB_BUFFS_T26X \ + (PVA_NUM_DMA_ADB_BUFFS_T26X - PVA_NUM_RESERVED_ADB_BUFFERS_T26X) + +#endif \ No newline at end of file diff --git a/drivers/video/tegra/host/pva/nvpva_ioctl_t264.h b/drivers/video/tegra/host/pva/nvpva_ioctl_t264.h index 4fd6ee6a..1602d72f 100644 --- a/drivers/video/tegra/host/pva/nvpva_ioctl_t264.h +++ b/drivers/video/tegra/host/pva/nvpva_ioctl_t264.h @@ -37,5 +37,37 @@ * R5 FW reserves one DMA channel for internal use. */ #define NVPVA_TASK_MAX_DMA_CHANNELS_T26X (15U) +/* NOTE: This is a re-definition of nvpva_dma_channel that + * contains T26x specific changes. Once T26x is public, + * this definition may be merged nvpva_dma_channel. + * + * Also note that the flags1 field has the following flags: + * - MSB for the HW Sequencer start index field in channel registers + * DMA_CHANNEL_HWSEQCNTL[1].bit[0] = flags1[0].bit[0]; + * - MSB for the HW Sequencer end index field in channel registers + * DMA_CHANNEL_HWSEQCNTL[2].bit[4] = flags1[0].bit[2]; + */ +struct nvpva_dma_channel_ex { + uint8_t descIndex; + uint8_t blockHeight; + uint16_t adbSize; + uint8_t vdbSize; + uint16_t adbOffset; + uint8_t vdbOffset; + uint32_t outputEnableMask; + uint32_t padValue; + uint8_t reqPerGrant; + uint8_t prefetchEnable; + uint8_t chRepFactor; + uint8_t hwseqStart; + uint8_t hwseqEnd; + uint8_t hwseqEnable; + uint8_t hwseqTraversalOrder; + uint8_t hwseqTxSelect; + uint8_t hwseqTriggerDone; + uint8_t hwseqFrameCount; + uint8_t hwseqConFrameSeq; + uint8_t flags1; +}; #endif /* __NVPVA_IOCTL_T264_H__ */ diff --git a/drivers/video/tegra/host/pva/pva_hwseq_t264.h b/drivers/video/tegra/host/pva/pva_hwseq_t264.h new file mode 100644 index 00000000..0e157765 --- /dev/null +++ b/drivers/video/tegra/host/pva/pva_hwseq_t264.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; If not, see . + */ + +#ifndef PVA_HWSEQ_T264_H +#define PVA_HWSEQ_T264_H + +#define PVA_HWSEQ_RAM_SIZE_T26X 2048U +#define PVA_HWSEQ_RAM_ID_MASK_T26X 0x1FFU +#define PVA_HWSEQ_RRA_ADDR 0xC0DAU +#define PVA_HWSEQ_RRA_MAX_NOCR 31U +#define PVA_HWSEQ_RRA_MAX_FRAME_COUNT 63U + +/** \brief Mask used to derive the MSB for HW sequencer + * buffer start index for a channel + */ +#define PVA_CH_FLAGS1_HWSEQ_START_IDX_MSB_MASK (1U) + +/** \brief Mask used to derive the MSB for HW sequencer + * buffer start index for a channel + */ +#define PVA_CH_FLAGS1_HWSEQ_START_IDX_MSB_SHIFT (0U) + +/** \brief Mask used to derive the MSB for HW sequencer + * buffer end index for a channel + */ +#define PVA_CH_FLAGS1_HWSEQ_END_IDX_MSB_MASK (1U << 2U) + +/** \brief Mask used to derive the MSB for HW sequencer + * buffer end index for a channel + */ +#define PVA_CH_FLAGS1_HWSEQ_END_IDX_MSB_SHIFT (2U) + +#define PVA_CH_FLAGS1_HWSEQ_START_IDX_MSB(flag) \ + ((flag & PVA_CH_FLAGS1_HWSEQ_START_IDX_MSB_MASK) \ + >> PVA_CH_FLAGS1_HWSEQ_START_IDX_MSB_SHIFT) + +#define PVA_CH_FLAGS1_HWSEQ_END_IDX_MSB(flag) \ + ((flag & PVA_CH_FLAGS1_HWSEQ_END_IDX_MSB_MASK) \ + >> PVA_CH_FLAGS1_HWSEQ_END_IDX_MSB_SHIFT) + +static inline bool is_rra_mode(u16 id) +{ + return (id == PVA_HWSEQ_RRA_ADDR); +} + +static inline u32 nvpva_get_hwseq_start_idx_t26x( + struct nvpva_dma_channel *user_ch) +{ + u32 idx = ((user_ch->hwseqStart & 0xFF) + | (PVA_CH_FLAGS1_HWSEQ_START_IDX_MSB(user_ch->flags1) << 8U)); + + return (idx & (u32)PVA_HWSEQ_RAM_ID_MASK_T26X); +} + +static inline u32 nvpva_get_hwseq_end_idx_t26x( + struct nvpva_dma_channel *user_ch) +{ + u32 idx = ((user_ch->hwseqEnd & 0xFF) + | (PVA_CH_FLAGS1_HWSEQ_END_IDX_MSB(user_ch->flags1) << 8U)); + + return (idx & (u32)PVA_HWSEQ_RAM_ID_MASK_T26X); +} + +static int validate_rra_mode(struct pva_hw_sweq_blob_s *blob, + struct pva_submit_task *task, + struct nvpva_dma_channel *dma_ch) +{ + const u8 *desc_entry = NULL; + const u8 *column = 0U; + uint32_t i = 0U; + uint32_t num_columns = 0U; + u32 end = nvpva_get_hwseq_end_idx_t26x(dma_ch) * 4U; + u8 *blob_end = &((uint8_t *)blob)[end + 4]; + // In each NOCR entry, 4 bytes are used for CRO + // and 4 bytes are used for Desc info + const u8 column_entry_size = 8U; + + if (task->pva->version < PVA_HW_GEN3) { + pr_err("Selected HWSEQ mode is not supported"); + return -EINVAL; + } + + if (dma_ch->hwseqFrameCount > PVA_HWSEQ_RRA_MAX_FRAME_COUNT) { + pr_err("Invalid HWSEQ frame count"); + return -EINVAL; + } + + if (blob->f_header.no_cr > PVA_HWSEQ_RRA_MAX_NOCR) { + pr_err("Invalid HWSEQ column count"); + return -EINVAL; + } + + if (blob->f_header.fr != 0) { + pr_err("Invalid HWSEQ repetition factor"); + return -EINVAL; + } + + num_columns = blob->f_header.no_cr + 1U; + column = (u8 *)&blob->cr_header; + desc_entry = (u8 *)&blob->desc_header; + + // Ensure there are sufficient CRO and Desc ID entries in the HWSEQ blob + if (((blob_end - column) / column_entry_size) < num_columns) { + pr_err("HWSEQ Program does not have enough columns"); + return -EINVAL; + } + + for (i = 0U; i < num_columns; i++) { + // In RRA mode, each HWSEQ column has only 1 descriptor + // Hence, we validate the first descriptor and ignore the second + // descriptor in each column + if ((*desc_entry == 0U) || + (*desc_entry > (NVPVA_TASK_MAX_DMA_DESCRIPTOR_ID_T26X))) { + pr_err("Invalid Descritor ID found in HW Sequencer"); + return -EINVAL; + } + desc_entry += column_entry_size; + } + + return 0; +} + +static inline bool hwseq_blob_validate_t26x(struct pva_hw_sweq_blob_s *blob, + struct pva_submit_task *task, + struct nvpva_dma_channel *dma_ch, + bool *validation_done) +{ + if (is_rra_mode(blob->f_header.fid)) { + *validation_done = true; + if (validate_rra_mode(blob, task, dma_ch) != 0) { + return false; + } + } else { + *validation_done = false; + } + return true; +} + +static inline void nvpva_task_dma_channel_mapping_t26x( + struct pva_dma_ch_config_s *ch, + struct nvpva_dma_channel *user_ch) +{ + /* DMA_CHANNEL_HWSEQCNTL_CHHWSEQSTART */ + /* Note: the MSB for HWSEQ start idx comes from bit 0 of flags1 field*/ + ch->hwseqcntl &= ~((u32)PVA_HWSEQ_RAM_ID_MASK_T26X); + ch->hwseqcntl |= nvpva_get_hwseq_start_idx_t26x(user_ch); + + /* DMA_CHANNEL_HWSEQCNTL_CHHWSEQEND */ + /* Note: the MSB for HWSEQ end idx comes from bit 2 of flags1 field*/ + ch->hwseqcntl &= (~((u32)PVA_HWSEQ_RAM_ID_MASK_T26X << 12U)); + ch->hwseqcntl |= (nvpva_get_hwseq_end_idx_t26x(user_ch) << 12U); + + /* DMA_CHANNEL_HWSEQFSCNTL_CHHWSEQFCNT*/ + ch->hwseqfscntl |= (((uint32_t)user_ch->hwseqConFrameSeq & 0x1U) << 0U); + + /* DMA_CHANNEL_HWSEQFSCNTL_CHHWSEQCFS*/ + ch->hwseqfscntl |= (((uint32_t)user_ch->hwseqFrameCount & 0x3FU) << 16U); +} + +#endif