forked from torvalds/linux
Permalink
Show file tree
Hide file tree
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
media: imx: imx8q: implement windsor encoder rpc interface
This part implements the windsor encoder rpc interface. Signed-off-by: Ming Qian <ming.qian@nxp.com> Signed-off-by: Shijie Qin <shijie.qin@nxp.com> Signed-off-by: Zhou Peng <eagle.zhou@nxp.com>
- Loading branch information
1 parent
b6e6926
commit 24cb9d25f8f3e58921074286fe42eedc10aa1214
Showing
4 changed files
with
1,617 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,218 @@ | ||
| // SPDX-License-Identifier: GPL-2.0 | ||
| /* | ||
| * Copyright 2020-2021 NXP | ||
| */ | ||
|
|
||
| #define TAG "IMX8Q" | ||
|
|
||
| #include <linux/init.h> | ||
| #include <linux/device.h> | ||
| #include <linux/ioctl.h> | ||
| #include <linux/list.h> | ||
| #include <linux/module.h> | ||
| #include <linux/kernel.h> | ||
| #include <linux/slab.h> | ||
| #include <linux/delay.h> | ||
| #include <linux/types.h> | ||
| #include "vpu.h" | ||
| #include "vpu_core.h" | ||
| #include "vpu_imx8q.h" | ||
| #include "vpu_rpc.h" | ||
| #include "vpu_log.h" | ||
|
|
||
| #define IMX8Q_CSR_CM0Px_ADDR_OFFSET 0x00000000 | ||
| #define IMX8Q_CSR_CM0Px_CPUWAIT 0x00000004 | ||
|
|
||
| #ifdef CONFIG_IMX_SCU | ||
| #include <linux/firmware/imx/ipc.h> | ||
| #include <linux/firmware/imx/svc/misc.h> | ||
|
|
||
| #define VPU_DISABLE_BITS 0x7 | ||
| #define VPU_IMX_DECODER_FUSE_OFFSET 14 | ||
| #define VPU_ENCODER_MASK 0x1 | ||
| #define VPU_DECODER_MASK 0x3UL | ||
| #define VPU_DECODER_H264_MASK 0x2UL | ||
| #define VPU_DECODER_HEVC_MASK 0x1UL | ||
|
|
||
| static u32 imx8q_fuse; | ||
|
|
||
| struct vpu_sc_msg_misc { | ||
| struct imx_sc_rpc_msg hdr; | ||
| u32 word; | ||
| } __packed; | ||
| #endif | ||
|
|
||
| int vpu_imx8q_set_system_cfg_common(struct vpu_rpc_system_config *config, | ||
| u32 regs, u32 core_id) | ||
| { | ||
| if (!config) | ||
| return -EINVAL; | ||
|
|
||
| switch (core_id) { | ||
| case 0: | ||
| config->malone_base_addr[0] = regs + DEC_MFD_XREG_SLV_BASE; | ||
| config->num_malones = 1; | ||
| config->num_windsors = 0; | ||
| break; | ||
| case 1: | ||
| config->windsor_base_addr[0] = regs + ENC_MFD_XREG_SLV_0_BASE; | ||
| config->num_windsors = 1; | ||
| config->num_malones = 0; | ||
| break; | ||
| case 2: | ||
| config->windsor_base_addr[0] = regs + ENC_MFD_XREG_SLV_1_BASE; | ||
| config->num_windsors = 1; | ||
| config->num_malones = 0; | ||
| break; | ||
| default: | ||
| return -EINVAL; | ||
| } | ||
| if (config->num_windsors) { | ||
| config->windsor_irq_pin[0x0][0x0] = WINDSOR_PAL_IRQ_PIN_L; | ||
| config->windsor_irq_pin[0x0][0x1] = WINDSOR_PAL_IRQ_PIN_H; | ||
| } | ||
|
|
||
| config->malone_base_addr[0x1] = 0x0; | ||
| config->hif_offset[0x0] = MFD_HIF; | ||
| config->hif_offset[0x1] = 0x0; | ||
|
|
||
| config->dpv_base_addr = 0x0; | ||
| config->dpv_irq_pin = 0x0; | ||
| config->pixif_base_addr = regs + DEC_MFD_XREG_SLV_BASE + MFD_PIX_IF; | ||
| config->cache_base_addr[0] = regs + MC_CACHE_0_BASE; | ||
| config->cache_base_addr[1] = regs + MC_CACHE_1_BASE; | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| int vpu_imx8q_boot_core(struct vpu_core *core) | ||
| { | ||
| csr_writel(core, IMX8Q_CSR_CM0Px_ADDR_OFFSET, core->fw.phys); | ||
| csr_writel(core, IMX8Q_CSR_CM0Px_CPUWAIT, 0); | ||
| return 0; | ||
| } | ||
|
|
||
| int vpu_imx8q_get_power_state(struct vpu_core *core) | ||
| { | ||
| if (csr_readl(core, IMX8Q_CSR_CM0Px_CPUWAIT) == 1) | ||
| return 0; | ||
| return 1; | ||
| } | ||
|
|
||
| int vpu_imx8q_on_firmware_loaded(struct vpu_core *core) | ||
| { | ||
| u8 *p; | ||
|
|
||
| p = core->fw.virt; | ||
| p[16] = core->vpu->res->plat_type; | ||
| p[17] = core->id; | ||
| p[18] = 1; | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| u32 vpu_imx8q_check_memory_region(dma_addr_t base, dma_addr_t addr, u32 size) | ||
| { | ||
| const struct vpu_rpc_region_t imx8q_regions[] = { | ||
| {0x00000000, 0x08000000, VPU_CORE_MEMORY_CACHED}, | ||
| {0x08000000, 0x10000000, VPU_CORE_MEMORY_UNCACHED}, | ||
| {0x10000000, 0x20000000, VPU_CORE_MEMORY_CACHED}, | ||
| {0x20000000, 0x40000000, VPU_CORE_MEMORY_UNCACHED} | ||
| }; | ||
| int i; | ||
|
|
||
| if (addr < base) | ||
| return VPU_CORE_MEMORY_INVALID; | ||
|
|
||
| addr -= base; | ||
| for (i = 0; i < ARRAY_SIZE(imx8q_regions); i++) { | ||
| const struct vpu_rpc_region_t *region = &imx8q_regions[i]; | ||
|
|
||
| if (addr >= region->start && addr + size < region->end) | ||
| return region->type; | ||
| } | ||
|
|
||
| return VPU_CORE_MEMORY_INVALID; | ||
| } | ||
|
|
||
| #ifdef CONFIG_IMX_SCU | ||
| u32 vpu_imx8q_get_fuse(void) | ||
| { | ||
| static u32 fuse_got; | ||
| struct imx_sc_ipc *ipc; | ||
| struct vpu_sc_msg_misc msg; | ||
| struct imx_sc_rpc_msg *hdr = &msg.hdr; | ||
| int ret; | ||
|
|
||
| if (fuse_got) | ||
| return imx8q_fuse; | ||
|
|
||
| ret = imx_scu_get_handle(&ipc); | ||
| if (ret) { | ||
| vpu_err("error: scu get handle fail: %d\n", ret); | ||
| return 0; | ||
| } | ||
|
|
||
| hdr->ver = IMX_SC_RPC_VERSION; | ||
| hdr->svc = IMX_SC_RPC_SVC_MISC; | ||
| hdr->func = IMX_SC_MISC_FUNC_OTP_FUSE_READ; | ||
| hdr->size = 2; | ||
|
|
||
| msg.word = VPU_DISABLE_BITS; | ||
|
|
||
| ret = imx_scu_call_rpc(ipc, &msg, true); | ||
| if (ret) | ||
| return 0; | ||
|
|
||
| imx8q_fuse = msg.word; | ||
| fuse_got = 1; | ||
| vpu_dbg(LVL_INFO, "imx8q fuse = 0x%x\n", imx8q_fuse); | ||
| return imx8q_fuse; | ||
| } | ||
|
|
||
| bool vpu_imx8q_check_codec(enum vpu_core_type type) | ||
| { | ||
| u32 fuse = vpu_imx8q_get_fuse(); | ||
|
|
||
| if (type == VPU_CORE_TYPE_ENC) { | ||
| if (fuse & VPU_ENCODER_MASK) | ||
| return false; | ||
| } else if (type == VPU_CORE_TYPE_DEC) { | ||
| fuse >>= VPU_IMX_DECODER_FUSE_OFFSET; | ||
| fuse &= VPU_DECODER_MASK; | ||
|
|
||
| if (fuse == VPU_DECODER_MASK) | ||
| return false; | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| bool vpu_imx8q_check_fmt(enum vpu_core_type type, u32 pixelfmt) | ||
| { | ||
| u32 fuse = vpu_imx8q_get_fuse(); | ||
|
|
||
| if (type == VPU_CORE_TYPE_DEC) { | ||
| fuse >>= VPU_IMX_DECODER_FUSE_OFFSET; | ||
| fuse &= VPU_DECODER_MASK; | ||
|
|
||
| if (fuse == VPU_DECODER_HEVC_MASK && pixelfmt == V4L2_PIX_FMT_HEVC) | ||
| return false; | ||
| if (fuse == VPU_DECODER_H264_MASK && pixelfmt == V4L2_PIX_FMT_H264) | ||
| return false; | ||
| if (fuse == VPU_DECODER_MASK) | ||
| return false; | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
| #else | ||
| bool vpu_imx8q_check_codec(enum vpu_core_type type) | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| bool vpu_imx8q_check_fmt(enum vpu_core_type type, u32 pixelfmt) | ||
| { | ||
| return true; | ||
| } | ||
| #endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| /* SPDX-License-Identifier: GPL-2.0 */ | ||
| /* | ||
| * Copyright 2020-2021 NXP | ||
| */ | ||
|
|
||
| #ifndef _IMX_VPU_8Q_H | ||
| #define _IMX_VPU_8Q_H | ||
|
|
||
| #define SCB_XREG_SLV_BASE 0x00000000 | ||
| #define SCB_SCB_BLK_CTRL 0x00070000 | ||
| #define SCB_BLK_CTRL_XMEM_RESET_SET 0x00000090 | ||
| #define SCB_BLK_CTRL_CACHE_RESET_SET 0x000000A0 | ||
| #define SCB_BLK_CTRL_CACHE_RESET_CLR 0x000000A4 | ||
| #define SCB_BLK_CTRL_SCB_CLK_ENABLE_SET 0x00000100 | ||
|
|
||
| #define XMEM_CONTROL 0x00041000 | ||
|
|
||
| #define MC_CACHE_0_BASE 0x00060000 | ||
| #define MC_CACHE_1_BASE 0x00068000 | ||
|
|
||
| #define DEC_MFD_XREG_SLV_BASE 0x00180000 | ||
| #define ENC_MFD_XREG_SLV_0_BASE 0x00800000 | ||
| #define ENC_MFD_XREG_SLV_1_BASE 0x00A00000 | ||
|
|
||
| #define MFD_HIF 0x0001C000 | ||
| #define MFD_HIF_MSD_REG_INTERRUPT_STATUS 0x00000018 | ||
| #define MFD_SIF 0x0001D000 | ||
| #define MFD_SIF_CTRL_STATUS 0x000000F0 | ||
| #define MFD_SIF_INTR_STATUS 0x000000F4 | ||
| #define MFD_MCX 0x00020800 | ||
| #define MFD_MCX_OFF 0x00000020 | ||
| #define MFD_PIX_IF 0x00020000 | ||
|
|
||
| #define MFD_BLK_CTRL 0x00030000 | ||
| #define MFD_BLK_CTRL_MFD_SYS_RESET_SET 0x00000000 | ||
| #define MFD_BLK_CTRL_MFD_SYS_RESET_CLR 0x00000004 | ||
| #define MFD_BLK_CTRL_MFD_SYS_CLOCK_ENABLE_SET 0x00000100 | ||
| #define MFD_BLK_CTRL_MFD_SYS_CLOCK_ENABLE_CLR 0x00000104 | ||
|
|
||
| #define VID_API_NUM_STREAMS 8 | ||
| #define VID_API_MAX_BUF_PER_STR 3 | ||
| #define VID_API_MAX_NUM_MVC_VIEWS 4 | ||
| #define MEDIAIP_MAX_NUM_MALONES 2 | ||
| #define MEDIAIP_MAX_NUM_MALONE_IRQ_PINS 2 | ||
| #define MEDIAIP_MAX_NUM_WINDSORS 1 | ||
| #define MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS 2 | ||
| #define MEDIAIP_MAX_NUM_CMD_IRQ_PINS 2 | ||
| #define MEDIAIP_MAX_NUM_MSG_IRQ_PINS 1 | ||
| #define MEDIAIP_MAX_NUM_TIMER_IRQ_PINS 4 | ||
| #define MEDIAIP_MAX_NUM_TIMER_IRQ_SLOTS 4 | ||
|
|
||
| #define WINDSOR_PAL_IRQ_PIN_L 0x4 | ||
| #define WINDSOR_PAL_IRQ_PIN_H 0x5 | ||
|
|
||
| struct vpu_rpc_system_config { | ||
| u32 cfg_cookie; | ||
|
|
||
| u32 num_malones; | ||
| u32 malone_base_addr[MEDIAIP_MAX_NUM_MALONES]; | ||
| u32 hif_offset[MEDIAIP_MAX_NUM_MALONES]; | ||
| u32 malone_irq_pin[MEDIAIP_MAX_NUM_MALONES][MEDIAIP_MAX_NUM_MALONE_IRQ_PINS]; | ||
| u32 malone_irq_target[MEDIAIP_MAX_NUM_MALONES][MEDIAIP_MAX_NUM_MALONE_IRQ_PINS]; | ||
|
|
||
| u32 num_windsors; | ||
| u32 windsor_base_addr[MEDIAIP_MAX_NUM_WINDSORS]; | ||
| u32 windsor_irq_pin[MEDIAIP_MAX_NUM_WINDSORS][MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS]; | ||
| u32 windsor_irq_target[MEDIAIP_MAX_NUM_WINDSORS][MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS]; | ||
|
|
||
| u32 cmd_irq_pin[MEDIAIP_MAX_NUM_CMD_IRQ_PINS]; | ||
| u32 cmd_irq_target[MEDIAIP_MAX_NUM_CMD_IRQ_PINS]; | ||
|
|
||
| u32 msg_irq_pin[MEDIAIP_MAX_NUM_MSG_IRQ_PINS]; | ||
| u32 msg_irq_target[MEDIAIP_MAX_NUM_MSG_IRQ_PINS]; | ||
|
|
||
| u32 sys_clk_freq; | ||
| u32 num_timers; | ||
| u32 timer_base_addr; | ||
| u32 timer_irq_pin[MEDIAIP_MAX_NUM_TIMER_IRQ_PINS]; | ||
| u32 timer_irq_target[MEDIAIP_MAX_NUM_TIMER_IRQ_PINS]; | ||
| u32 timer_slots[MEDIAIP_MAX_NUM_TIMER_IRQ_SLOTS]; | ||
|
|
||
| u32 gic_base_addr; | ||
| u32 uart_base_addr; | ||
|
|
||
| u32 dpv_base_addr; | ||
| u32 dpv_irq_pin; | ||
| u32 dpv_irq_target; | ||
|
|
||
| u32 pixif_base_addr; | ||
|
|
||
| u32 pal_trace_level; | ||
| u32 pal_trace_destination; | ||
|
|
||
| u32 pal_trace_level1; | ||
| u32 pal_trace_destination1; | ||
|
|
||
| u32 uHeapBase; | ||
| u32 uHeapSize; | ||
|
|
||
| u32 cache_base_addr[2]; | ||
| }; | ||
|
|
||
| int vpu_imx8q_setup_dec(struct vpu_dev *vpu); | ||
| int vpu_imx8q_setup_enc(struct vpu_dev *vpu); | ||
| int vpu_imx8q_setup(struct vpu_dev *vpu); | ||
| int vpu_imx8q_reset(struct vpu_dev *vpu); | ||
| int vpu_imx8q_set_system_cfg_common(struct vpu_rpc_system_config *config, | ||
| u32 regs, u32 core_id); | ||
| int vpu_imx8q_boot_core(struct vpu_core *core); | ||
| int vpu_imx8q_get_power_state(struct vpu_core *core); | ||
| int vpu_imx8q_on_firmware_loaded(struct vpu_core *core); | ||
| u32 vpu_imx8q_check_memory_region(dma_addr_t base, dma_addr_t addr, u32 size); | ||
| bool vpu_imx8q_check_codec(enum vpu_core_type type); | ||
| bool vpu_imx8q_check_fmt(enum vpu_core_type type, u32 pixelfmt); | ||
|
|
||
| #endif |
Oops, something went wrong.