blob: db709a0d028153c767e7d3803bfe37c967e2ba7a [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#include "msm_vidc_debug.h"
#include "hfi_common.h"
#define VIDC_CPU_BASE_OFFS_AR50_LT 0x000A0000
#define VIDEO_GCC_BASE_OFFS_AR50_LT 0x00000000
#define VIDEO_CC_BASE_OFFS_AR50_LT 0x00100000
#define VIDC_CPU_CS_BASE_OFFS_AR50_LT (VIDC_CPU_BASE_OFFS_AR50_LT)
#define VIDC_CPU_IC_BASE_OFFS_AR50_LT (VIDC_CPU_BASE_OFFS_AR50_LT)
#define VIDC_CPU_CS_A2HSOFTINTCLR_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x1C)
#define VIDC_CPU_CS_VMIMSG_AR50_LTi (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x34)
#define VIDC_CPU_CS_VMIMSGAG0_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x38)
#define VIDC_CPU_CS_VMIMSGAG1_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x3C)
#define VIDC_CPU_CS_VMIMSGAG2_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x40)
#define VIDC_CPU_CS_VMIMSGAG3_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x44)
#define VIDC_CPU_CS_SCIACMD_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x48)
/* HFI_CTRL_STATUS */
#define VIDC_CPU_CS_SCIACMDARG0_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x4C)
#define VIDC_CPU_CS_SCIACMDARG0_BMSK_AR50_LT 0xff
#define VIDC_CPU_CS_SCIACMDARG0_SHFT_AR50_LT 0x0
#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK_AR50_LT 0xfe
#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_SHFT_AR50_LT 0x1
#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_STATUS_BMSK_AR50_LT 0x1
#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_STATUS_SHFT_AR50_LT 0x0
#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY_AR50_LT 0x100
#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK_AR50_LT 0x40000000
/* HFI_QTBL_INFO */
#define VIDC_CPU_CS_SCIACMDARG1_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x50)
/* HFI_QTBL_ADDR */
#define VIDC_CPU_CS_SCIACMDARG2_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x54)
/* HFI_VERSION_INFO */
#define VIDC_CPU_CS_SCIACMDARG3_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x58)
/* VIDC_SFR_ADDR */
#define VIDC_CPU_CS_SCIBCMD_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x5C)
/* VIDC_MMAP_ADDR */
#define VIDC_CPU_CS_SCIBCMDARG0_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x60)
/* VIDC_UC_REGION_ADDR */
#define VIDC_CPU_CS_SCIBARG1_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x64)
/* VIDC_UC_REGION_ADDR */
#define VIDC_CPU_CS_SCIBARG2_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x68)
#define VIDC_CPU_IC_SOFTINT_EN_AR50_LT (VIDC_CPU_IC_BASE_OFFS_AR50_LT + 0x148)
#define VIDC_CPU_IC_SOFTINT_AR50_LT (VIDC_CPU_IC_BASE_OFFS_AR50_LT + 0x150)
#define VIDC_CPU_IC_SOFTINT_H2A_BMSK_AR50_LT 0x8000
#define VIDC_CPU_IC_SOFTINT_H2A_SHFT_AR50_LT 0x1
/*
* --------------------------------------------------------------------------
* MODULE: vidc_wrapper
* --------------------------------------------------------------------------
*/
#define VIDC_WRAPPER_BASE_OFFS_AR50_LT 0x000B0000
#define VIDC_WRAPPER_HW_VERSION_AR50_LT (VIDC_WRAPPER_BASE_OFFS_AR50_LT + 0x00)
#define VIDC_WRAPPER_HW_VERSION_MAJOR_VERSION_MASK_AR50_LT 0x78000000
#define VIDC_WRAPPER_HW_VERSION_MAJOR_VERSION_SHIFT_AR50_LT 28
#define VIDC_WRAPPER_HW_VERSION_MINOR_VERSION_MASK_AR50_LT 0xFFF0000
#define VIDC_WRAPPER_HW_VERSION_MINOR_VERSION_SHIFT_AR50_LT 16
#define VIDC_WRAPPER_HW_VERSION_STEP_VERSION_MASK_AR50_LT 0xFFFF
#define VIDC_WRAPPER_CLOCK_CONFIG_AR50_LT (VIDC_WRAPPER_BASE_OFFS_AR50_LT + 0x04)
#define VIDC_WRAPPER_INTR_STATUS_AR50_LT (VIDC_WRAPPER_BASE_OFFS_AR50_LT + 0x0C)
#define VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK_AR50_LT 0x10
#define VIDC_WRAPPER_INTR_STATUS_A2HWD_SHFT_AR50_LT 0x4
#define VIDC_WRAPPER_INTR_STATUS_A2H_BMSK_AR50_LT 0x4
#define VIDC_WRAPPER_INTR_STATUS_A2H_SHFT_AR50_LT 0x2
#define VIDC_WRAPPER_INTR_MASK_AR50_LT (VIDC_WRAPPER_BASE_OFFS_AR50_LT + 0x10)
#define VIDC_WRAPPER_INTR_MASK_A2HWD_BMSK_AR50_LT 0x10
#define VIDC_WRAPPER_INTR_MASK_A2HWD_SHFT_AR50_LT 0x4
#define VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK_AR50_LT 0x8
#define VIDC_WRAPPER_INTR_MASK_A2HCPU_BMSK_AR50_LT 0x4
#define VIDC_WRAPPER_INTR_MASK_A2HCPU_SHFT_AR50_LT 0x2
#define VIDC_WRAPPER_INTR_CLEAR_A2HWD_BMSK_AR50_LT 0x10
#define VIDC_WRAPPER_INTR_CLEAR_A2HWD_SHFT_AR50_LT 0x4
#define VIDC_WRAPPER_INTR_CLEAR_A2H_BMSK_AR50_LT 0x4
#define VIDC_WRAPPER_INTR_CLEAR_A2H_SHFT_AR50_LT 0x2
/*
* --------------------------------------------------------------------------
* MODULE: tz_wrapper
* --------------------------------------------------------------------------
*/
#define VIDC_WRAPPER_TZ_BASE_OFFS 0x000C0000
#define VIDC_WRAPPER_TZ_CPU_CLOCK_CONFIG (VIDC_WRAPPER_TZ_BASE_OFFS)
#define VIDC_WRAPPER_TZ_CPU_STATUS (VIDC_WRAPPER_TZ_BASE_OFFS + 0x10)
#define VIDC_CTRL_INIT_AR50_LT VIDC_CPU_CS_SCIACMD_AR50_LT
#define VIDC_CTRL_STATUS_AR50_LT VIDC_CPU_CS_SCIACMDARG0_AR50_LT
#define VIDC_CTRL_ERROR_STATUS__M_AR50_LT \
VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK_AR50_LT
#define VIDC_CTRL_INIT_IDLE_MSG_BMSK_AR50_LT \
VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK_AR50_LT
#define VIDC_CTRL_STATUS_PC_READY_AR50_LT \
VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY_AR50_LT
#define VIDC_QTBL_INFO_AR50_LT VIDC_CPU_CS_SCIACMDARG1_AR50_LT
#define VIDC_QTBL_ADDR_AR50_LT VIDC_CPU_CS_SCIACMDARG2_AR50_LT
#define VIDC_VERSION_INFO_AR50_LT VIDC_CPU_CS_SCIACMDARG3_AR50_LT
#define VIDC_SFR_ADDR_AR50_LT VIDC_CPU_CS_SCIBCMD_AR50_LT
#define VIDC_MMAP_ADDR_AR50_LT VIDC_CPU_CS_SCIBCMDARG0_AR50_LT
#define VIDC_UC_REGION_ADDR_AR50_LT VIDC_CPU_CS_SCIBARG1_AR50_LT
#define VIDC_UC_REGION_SIZE_AR50_LT VIDC_CPU_CS_SCIBARG2_AR50_LT
void __interrupt_init_ar50_lt(struct venus_hfi_device *device, u32 sid)
{
__write_register(device, VIDC_WRAPPER_INTR_MASK_AR50_LT,
VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK_AR50_LT, sid);
}
void __setup_ucregion_memory_map_ar50_lt(struct venus_hfi_device *device, u32 sid)
{
__write_register(device, VIDC_UC_REGION_ADDR_AR50_LT,
(u32)device->iface_q_table.align_device_addr, sid);
__write_register(device, VIDC_UC_REGION_SIZE_AR50_LT, SHARED_QSIZE, sid);
__write_register(device, VIDC_QTBL_ADDR_AR50_LT,
(u32)device->iface_q_table.align_device_addr, sid);
__write_register(device, VIDC_QTBL_INFO_AR50_LT, 0x01, sid);
if (device->sfr.align_device_addr)
__write_register(device, VIDC_SFR_ADDR_AR50_LT,
(u32)device->sfr.align_device_addr, sid);
if (device->qdss.align_device_addr)
__write_register(device, VIDC_MMAP_ADDR_AR50_LT,
(u32)device->qdss.align_device_addr, sid);
}
void __power_off_ar50_lt(struct venus_hfi_device *device)
{
if (!device->power_enabled)
return;
if (!(device->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK_AR50_LT))
disable_irq_nosync(device->hal_data->irq);
device->intr_status = 0;
__disable_unprepare_clks(device);
if (__disable_regulators(device))
d_vpr_e("Failed to disable regulators\n");
if (__unvote_buses(device, DEFAULT_SID))
d_vpr_e("Failed to unvote for buses\n");
device->power_enabled = false;
}
int __prepare_pc_ar50_lt(struct venus_hfi_device *device)
{
int rc = 0;
u32 wfi_status = 0, idle_status = 0, pc_ready = 0;
u32 ctrl_status = 0;
u32 count = 0, max_tries = 10;
ctrl_status = __read_register(device, VIDC_CTRL_STATUS_AR50_LT, DEFAULT_SID);
pc_ready = ctrl_status & VIDC_CTRL_STATUS_PC_READY_AR50_LT;
idle_status = ctrl_status & BIT(30);
if (pc_ready) {
d_vpr_l("Already in pc_ready state\n");
return 0;
}
wfi_status = BIT(0) & __read_register(device,
VIDC_WRAPPER_TZ_CPU_STATUS, DEFAULT_SID);
if (!wfi_status || !idle_status) {
d_vpr_e("Skipping PC, wfi status not set\n");
goto skip_power_off;
}
rc = __prepare_pc(device);
if (rc) {
d_vpr_e("Failed __prepare_pc %d\n", rc);
goto skip_power_off;
}
while (count < max_tries) {
wfi_status = BIT(0) & __read_register(device,
VIDC_WRAPPER_TZ_CPU_STATUS, DEFAULT_SID);
ctrl_status = __read_register(device,
VIDC_CTRL_STATUS_AR50_LT, DEFAULT_SID);
pc_ready = ctrl_status & VIDC_CTRL_STATUS_PC_READY_AR50_LT;
if (wfi_status && pc_ready)
break;
usleep_range(150, 250);
count++;
}
if (count == max_tries) {
d_vpr_e("Skip PC. Core is not in right state\n");
goto skip_power_off;
}
return rc;
skip_power_off:
d_vpr_e("Skip PC, wfi=%#x, idle=%#x, pcr=%#x, ctrl=%#x)\n",
wfi_status, idle_status, pc_ready, ctrl_status);
return -EAGAIN;
}
void __raise_interrupt_ar50_lt(struct venus_hfi_device *device, u32 sid)
{
__write_register(device, VIDC_CPU_IC_SOFTINT_AR50_LT,
VIDC_CPU_IC_SOFTINT_H2A_SHFT_AR50_LT, sid);
}
void __core_clear_interrupt_ar50_lt(struct venus_hfi_device *device)
{
u32 intr_status = 0, mask = 0;
if (!device) {
d_vpr_e("%s: NULL device\n", __func__);
return;
}
intr_status = __read_register(device, VIDC_WRAPPER_INTR_STATUS_AR50_LT, DEFAULT_SID);
mask = (VIDC_WRAPPER_INTR_STATUS_A2H_BMSK_AR50_LT |
VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK_AR50_LT |
VIDC_CTRL_INIT_IDLE_MSG_BMSK_AR50_LT);
if (intr_status & mask) {
device->intr_status |= intr_status;
device->reg_count++;
d_vpr_l(
"INTERRUPT for device: %pK: times: %d interrupt_status: %d\n",
device, device->reg_count, intr_status);
} else {
device->spur_count++;
}
__write_register(device, VIDC_CPU_CS_A2HSOFTINTCLR_AR50_LT, 1, DEFAULT_SID);
}
int __boot_firmware_ar50_lt(struct venus_hfi_device *device, u32 sid)
{
int rc = 0;
u32 ctrl_init_val = 0, ctrl_status = 0, count = 0, max_tries = 1000;
ctrl_init_val = BIT(0);
__write_register(device, VIDC_CTRL_INIT_AR50_LT, ctrl_init_val, sid);
while (!ctrl_status && count < max_tries) {
ctrl_status = __read_register(device, VIDC_CTRL_STATUS_AR50_LT, sid);
if ((ctrl_status & VIDC_CTRL_ERROR_STATUS__M_AR50_LT) == 0x4) {
s_vpr_e(sid, "invalid setting for UC_REGION\n");
break;
}
usleep_range(50, 100);
count++;
}
if (count >= max_tries) {
s_vpr_e(sid, "Error booting up vidc firmware\n");
rc = -ETIME;
}
/* Enable interrupt before sending commands to venus */
__write_register(device, VIDC_CPU_IC_SOFTINT_EN_AR50_LT, 0x1, sid);
return rc;
}