2071 lines
58 KiB
C
2071 lines
58 KiB
C
|
/*
|
||
|
* Samsung Exynos5 SoC series FIMC-IS driver
|
||
|
*
|
||
|
* exynos5 fimc-is video functions
|
||
|
*
|
||
|
* Copyright (c) 2011 Samsung Electronics Co., Ltd
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License version 2 as
|
||
|
* published by the Free Software Foundation.
|
||
|
*/
|
||
|
|
||
|
#include <linux/memblock.h>
|
||
|
#include <linux/slab.h>
|
||
|
#include <linux/irq.h>
|
||
|
#include <linux/interrupt.h>
|
||
|
#include <linux/delay.h>
|
||
|
#include <linux/version.h>
|
||
|
#include <linux/gpio.h>
|
||
|
#include <linux/clk.h>
|
||
|
#include <linux/regulator/consumer.h>
|
||
|
#include <linux/videodev2.h>
|
||
|
#include <linux/videodev2_exynos_camera.h>
|
||
|
#include <linux/module.h>
|
||
|
#include <linux/moduleparam.h>
|
||
|
#include <linux/platform_device.h>
|
||
|
#include <media/v4l2-ctrls.h>
|
||
|
#include <media/v4l2-device.h>
|
||
|
#include <media/v4l2-subdev.h>
|
||
|
#include <soc/samsung/tmu.h>
|
||
|
#include <linux/isp_cooling.h>
|
||
|
#include <linux/cpuidle.h>
|
||
|
#include <linux/soc/samsung/exynos-soc.h>
|
||
|
#include <soc/samsung/bts.h>
|
||
|
#ifdef CONFIG_CMU_EWF
|
||
|
#include <soc/samsung/cmu_ewf.h>
|
||
|
#endif
|
||
|
#if defined(CONFIG_SECURE_CAMERA_USE)
|
||
|
#include <linux/smc.h>
|
||
|
#endif
|
||
|
|
||
|
#include <linux/of_fdt.h>
|
||
|
#include <linux/of_reserved_mem.h>
|
||
|
|
||
|
#ifdef CONFIG_EXYNOS_BUSMONITOR
|
||
|
#include <linux/exynos-busmon.h>
|
||
|
#endif
|
||
|
|
||
|
#if IS_ENABLED(CONFIG_EXYNOS_SNAPSHOT)
|
||
|
#include <linux/exynos-ss.h>
|
||
|
#elif IS_ENABLED(CONFIG_DEBUG_SNAPSHOT)
|
||
|
#include <linux/debug-snapshot.h>
|
||
|
#endif
|
||
|
|
||
|
#ifdef CONFIG_EXYNOS_BCM_DBG_GNR
|
||
|
#include <soc/samsung/exynos-bcm_dbg.h>
|
||
|
#endif
|
||
|
|
||
|
#include "fimc-is-resourcemgr.h"
|
||
|
#include "fimc-is-hw.h"
|
||
|
#include "fimc-is-debug.h"
|
||
|
#include "fimc-is-core.h"
|
||
|
#include "fimc-is-dvfs.h"
|
||
|
#include "fimc-is-clk-gate.h"
|
||
|
#if !defined(ENABLE_IS_CORE)
|
||
|
#include "fimc-is-interface-library.h"
|
||
|
#include "hardware/fimc-is-hw-control.h"
|
||
|
#endif
|
||
|
|
||
|
#if defined(SECURE_CAMERA_FACE)
|
||
|
#include <linux/ion_exynos.h>
|
||
|
#endif
|
||
|
|
||
|
#ifdef CONFIG_SCHED_EMS
|
||
|
#include <linux/ems.h>
|
||
|
struct gb_qos_request gb_req = {
|
||
|
.name = "camera_ehmp_boost",
|
||
|
};
|
||
|
#endif
|
||
|
|
||
|
#define CLUSTER_MIN_MASK 0x0000FFFF
|
||
|
#define CLUSTER_MIN_SHIFT 0
|
||
|
#define CLUSTER_MAX_MASK 0xFFFF0000
|
||
|
#define CLUSTER_MAX_SHIFT 16
|
||
|
|
||
|
#if defined(QOS_INTCAM)
|
||
|
struct pm_qos_request exynos_isp_qos_int_cam;
|
||
|
#endif
|
||
|
struct pm_qos_request exynos_isp_qos_int;
|
||
|
struct pm_qos_request exynos_isp_qos_mem;
|
||
|
struct pm_qos_request exynos_isp_qos_cam;
|
||
|
struct pm_qos_request exynos_isp_qos_disp;
|
||
|
struct pm_qos_request exynos_isp_qos_hpg;
|
||
|
struct pm_qos_request exynos_isp_qos_cluster0_min;
|
||
|
struct pm_qos_request exynos_isp_qos_cluster0_max;
|
||
|
struct pm_qos_request exynos_isp_qos_cluster1_min;
|
||
|
struct pm_qos_request exynos_isp_qos_cluster1_max;
|
||
|
struct pm_qos_request exynos_isp_qos_cpu_online_min;
|
||
|
#ifdef CONFIG_CMU_EWF
|
||
|
unsigned int idx_ewf;
|
||
|
#endif
|
||
|
|
||
|
#define C0MIN_QOS_ADD(freq) pm_qos_add_request(&exynos_isp_qos_cluster0_min, PM_QOS_CLUSTER0_FREQ_MIN, freq * 1000)
|
||
|
#define C0MIN_QOS_DEL() pm_qos_remove_request(&exynos_isp_qos_cluster0_min)
|
||
|
#define C0MIN_QOS_UPDATE(freq) pm_qos_update_request(&exynos_isp_qos_cluster0_min, freq * 1000)
|
||
|
#define C0MAX_QOS_ADD(freq) pm_qos_add_request(&exynos_isp_qos_cluster0_max, PM_QOS_CLUSTER0_FREQ_MAX, freq * 1000)
|
||
|
#define C0MAX_QOS_DEL() pm_qos_remove_request(&exynos_isp_qos_cluster0_max)
|
||
|
#define C0MAX_QOS_UPDATE(freq) pm_qos_update_request(&exynos_isp_qos_cluster0_max, freq * 1000)
|
||
|
#define C1MIN_QOS_ADD(freq) pm_qos_add_request(&exynos_isp_qos_cluster1_min, PM_QOS_CLUSTER1_FREQ_MIN, freq * 1000)
|
||
|
#define C1MIN_QOS_DEL() pm_qos_remove_request(&exynos_isp_qos_cluster1_min)
|
||
|
#define C1MIN_QOS_UPDATE(freq) pm_qos_update_request(&exynos_isp_qos_cluster1_min, freq * 1000)
|
||
|
#define C1MAX_QOS_ADD(freq) pm_qos_add_request(&exynos_isp_qos_cluster1_max, PM_QOS_CLUSTER1_FREQ_MAX, freq * 1000)
|
||
|
#define C1MAX_QOS_DEL() pm_qos_remove_request(&exynos_isp_qos_cluster1_max)
|
||
|
#define C1MAX_QOS_UPDATE(freq) pm_qos_update_request(&exynos_isp_qos_cluster1_max, freq * 1000)
|
||
|
|
||
|
extern struct fimc_is_sysfs_debug sysfs_debug;
|
||
|
extern int fimc_is_sensor_runtime_suspend(struct device *dev);
|
||
|
extern int fimc_is_sensor_runtime_resume(struct device *dev);
|
||
|
|
||
|
#ifdef ENABLE_IS_CORE
|
||
|
static int fimc_is_resourcemgr_allocmem(struct fimc_is_resourcemgr *resourcemgr)
|
||
|
{
|
||
|
struct fimc_is_mem *mem = &resourcemgr->mem;
|
||
|
struct fimc_is_minfo *minfo = &resourcemgr->minfo;
|
||
|
int ret = 0;
|
||
|
|
||
|
minfo->total_size = FW_MEM_SIZE;
|
||
|
#if defined (FW_SUSPEND_RESUME)
|
||
|
minfo->total_size += FW_BACKUP_SIZE;
|
||
|
#endif
|
||
|
#if defined (ENABLE_ODC)
|
||
|
minfo->total_size += SIZE_ODC_INTERNAL_BUF * NUM_ODC_INTERNAL_BUF;
|
||
|
#endif
|
||
|
#if defined (ENABLE_VDIS)
|
||
|
minfo->total_size += SIZE_DIS_INTERNAL_BUF * NUM_DIS_INTERNAL_BUF;
|
||
|
#endif
|
||
|
#if defined (ENABLE_DNR_IN_TPU)
|
||
|
minfo->total_size += SIZE_DNR_INTERNAL_BUF * NUM_DNR_INTERNAL_BUF;
|
||
|
#endif
|
||
|
#if defined (ENABLE_FD_DMA_INPUT)
|
||
|
minfo->total_size += SIZE_LHFD_SHOT_BUF * MAX_LHFD_SHOT_BUF;
|
||
|
#endif
|
||
|
|
||
|
minfo->pb_fw = CALL_PTR_MEMOP(mem, alloc, mem->default_ctx, minfo->total_size, NULL, 0);
|
||
|
if (IS_ERR(minfo->pb_fw)) {
|
||
|
err("failed to allocate buffer for FW");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
|
||
|
#if defined (ENABLE_FD_SW)
|
||
|
minfo->pb_lhfd = CALL_PTR_MEMOP(mem, alloc, mem->default_ctx, LHFD_MAP_SIZE, NULL, 0);
|
||
|
if (IS_ERR(minfo->pb_lhfd)) {
|
||
|
err("failed to allocate buffer for LHFD_MAP");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
minfo->total_size += minfo->pb_lhfd->size;
|
||
|
#endif
|
||
|
|
||
|
probe_info("[RSC] Internal memory size (aligned) : %08lx\n", minfo->total_size);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int fimc_is_resourcemgr_initmem(struct fimc_is_resourcemgr *resourcemgr)
|
||
|
{
|
||
|
struct fimc_is_minfo *minfo = NULL;
|
||
|
int ret = 0;
|
||
|
u32 offset;
|
||
|
|
||
|
ret = fimc_is_resourcemgr_allocmem(resourcemgr);
|
||
|
if (ret) {
|
||
|
err("Couldn't alloc for FIMC-IS firmware\n");
|
||
|
ret = -ENOMEM;
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
minfo = &resourcemgr->minfo;
|
||
|
/* set information */
|
||
|
resourcemgr->minfo.dvaddr = CALL_BUFOP(minfo->pb_fw, dvaddr, minfo->pb_fw);
|
||
|
resourcemgr->minfo.kvaddr = CALL_BUFOP(minfo->pb_fw, kvaddr, minfo->pb_fw);
|
||
|
|
||
|
offset = SHARED_OFFSET;
|
||
|
resourcemgr->minfo.dvaddr_fshared = resourcemgr->minfo.dvaddr + offset;
|
||
|
resourcemgr->minfo.kvaddr_fshared = resourcemgr->minfo.kvaddr + offset;
|
||
|
|
||
|
offset = FW_MEM_SIZE - PARAM_REGION_SIZE;
|
||
|
resourcemgr->minfo.dvaddr_region = resourcemgr->minfo.dvaddr + offset;
|
||
|
resourcemgr->minfo.kvaddr_region = resourcemgr->minfo.kvaddr + offset;
|
||
|
|
||
|
offset = FW_MEM_SIZE;
|
||
|
#if defined (FW_SUSPEND_RESUME)
|
||
|
offset += FW_BACKUP_SIZE;
|
||
|
#endif
|
||
|
|
||
|
#if defined(ENABLE_ODC) || defined(ENABLE_VDIS) || defined(ENABLE_DNR_IN_TPU)
|
||
|
resourcemgr->minfo.dvaddr_tpu = resourcemgr->minfo.dvaddr + offset;
|
||
|
resourcemgr->minfo.kvaddr_tpu = resourcemgr->minfo.kvaddr + offset;
|
||
|
#if defined (ENABLE_ODC)
|
||
|
offset += (SIZE_ODC_INTERNAL_BUF * NUM_ODC_INTERNAL_BUF);
|
||
|
#endif
|
||
|
#if defined (ENABLE_VDIS)
|
||
|
offset += (SIZE_DIS_INTERNAL_BUF * NUM_DIS_INTERNAL_BUF);
|
||
|
#endif
|
||
|
#if defined (ENABLE_DNR_IN_TPU)
|
||
|
offset += (SIZE_DNR_INTERNAL_BUF * NUM_DNR_INTERNAL_BUF);
|
||
|
#endif
|
||
|
#else
|
||
|
resourcemgr->minfo.dvaddr_tpu = 0;
|
||
|
resourcemgr->minfo.kvaddr_tpu = 0;
|
||
|
#endif
|
||
|
|
||
|
#if defined(ENABLE_FD_SW)
|
||
|
resourcemgr->minfo.dvaddr_lhfd = CALL_BUFOP(minfo->pb_lhfd, dvaddr, minfo->pb_lhfd);
|
||
|
resourcemgr->minfo.kvaddr_lhfd = CALL_BUFOP(minfo->pb_lhfd, kvaddr, minfo->pb_lhfd);
|
||
|
#else
|
||
|
resourcemgr->minfo.dvaddr_lhfd = 0;
|
||
|
resourcemgr->minfo.kvaddr_lhfd = 0;
|
||
|
#endif
|
||
|
resourcemgr->minfo.kvaddr_debug_cnt = resourcemgr->minfo.kvaddr +
|
||
|
DEBUG_REGION_OFFSET + DEBUG_REGION_SIZE;
|
||
|
|
||
|
probe_info("[RSC] Kernel virtual for internal: 0x%lx\n", resourcemgr->minfo.kvaddr);
|
||
|
probe_info("[RSC] Device virtual for internal: 0x%llx\n", resourcemgr->minfo.dvaddr);
|
||
|
probe_info("[RSC] fimc_is_init_mem done\n");
|
||
|
|
||
|
p_err:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
#ifndef ENABLE_RESERVED_MEM
|
||
|
static int fimc_is_resourcemgr_deinitmem(struct fimc_is_resourcemgr *resourcemgr)
|
||
|
{
|
||
|
struct fimc_is_minfo *minfo = &resourcemgr->minfo;
|
||
|
int ret = 0;
|
||
|
|
||
|
CALL_VOID_BUFOP(minfo->pb_fw, free, minfo->pb_setfile);
|
||
|
#if defined (ENABLE_FD_SW)
|
||
|
CALL_VOID_BUFOP(minfo->pb_lhfd, free, minfo->pb_lhfd);
|
||
|
#endif
|
||
|
return ret;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#else /* #ifdef ENABLE_IS_CORE */
|
||
|
static int fimc_is_resourcemgr_allocmem(struct fimc_is_resourcemgr *resourcemgr)
|
||
|
{
|
||
|
struct fimc_is_mem *mem = &resourcemgr->mem;
|
||
|
struct fimc_is_minfo *minfo = &resourcemgr->minfo;
|
||
|
size_t tpu_size = 0;
|
||
|
#if !defined(ENABLE_DYNAMIC_MEM) && defined(ENABLE_TNR)
|
||
|
size_t tnr_size = ((SIZE_TNR_IMAGE_BUF + SIZE_TNR_WEIGHT_BUF) * NUM_OF_TNR_BUF);
|
||
|
#endif
|
||
|
int i;
|
||
|
|
||
|
minfo->total_size = 0;
|
||
|
/* setfile */
|
||
|
minfo->pb_setfile = CALL_PTR_MEMOP(mem, alloc, mem->default_ctx, SETFILE_SIZE, NULL, 0);
|
||
|
if (IS_ERR_OR_NULL(minfo->pb_setfile)) {
|
||
|
err("failed to allocate buffer for SETFILE");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
minfo->total_size += minfo->pb_setfile->size;
|
||
|
|
||
|
/* calibration data for each sensor postion */
|
||
|
for (i = 0; i < SENSOR_POSITION_MAX; i++) {
|
||
|
minfo->pb_cal[i] = CALL_PTR_MEMOP(mem, alloc, mem->default_ctx, CALDATA_SIZE, NULL, 0);
|
||
|
if (IS_ERR_OR_NULL(minfo->pb_cal[i])) {
|
||
|
err("failed to allocate buffer for REAR_CALDATA");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
minfo->total_size += minfo->pb_cal[i]->size;
|
||
|
}
|
||
|
|
||
|
/* library logging */
|
||
|
minfo->pb_debug = mem->kmalloc(DEBUG_REGION_SIZE + 0x10, 16);
|
||
|
if (IS_ERR_OR_NULL(minfo->pb_debug)) {
|
||
|
/* retry by ION */
|
||
|
minfo->pb_debug = CALL_PTR_MEMOP(mem, alloc, mem->default_ctx, DEBUG_REGION_SIZE + 0x10, NULL, 0);
|
||
|
if (IS_ERR_OR_NULL(minfo->pb_debug)) {
|
||
|
err("failed to allocate buffer for DEBUG_REGION");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
}
|
||
|
minfo->total_size += minfo->pb_debug->size;
|
||
|
|
||
|
/* library event logging */
|
||
|
minfo->pb_event = mem->kmalloc(EVENT_REGION_SIZE + 0x10, 16);
|
||
|
if (IS_ERR_OR_NULL(minfo->pb_event)) {
|
||
|
/* retry by ION */
|
||
|
minfo->pb_event = CALL_PTR_MEMOP(mem, alloc, mem->default_ctx, EVENT_REGION_SIZE + 0x10, NULL, 0);
|
||
|
if (IS_ERR_OR_NULL(minfo->pb_event)) {
|
||
|
err("failed to allocate buffer for EVENT_REGION");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
}
|
||
|
minfo->total_size += minfo->pb_event->size;
|
||
|
|
||
|
/* data region */
|
||
|
minfo->pb_dregion = CALL_PTR_MEMOP(mem, alloc, mem->default_ctx, DATA_REGION_SIZE, NULL, 0);
|
||
|
if (IS_ERR_OR_NULL(minfo->pb_dregion)) {
|
||
|
err("failed to allocate buffer for DATA_REGION");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
minfo->total_size += minfo->pb_dregion->size;
|
||
|
|
||
|
/* parameter region */
|
||
|
minfo->pb_pregion = CALL_PTR_MEMOP(mem, alloc, mem->default_ctx,
|
||
|
(FIMC_IS_STREAM_COUNT * PARAM_REGION_SIZE), NULL, 0);
|
||
|
if (IS_ERR_OR_NULL(minfo->pb_pregion)) {
|
||
|
err("failed to allocate buffer for PARAM_REGION");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
minfo->total_size += minfo->pb_pregion->size;
|
||
|
|
||
|
/* fshared data region */
|
||
|
minfo->pb_fshared = CALL_PTR_MEMOP(mem, alloc, mem->default_ctx, FSHARED_REGION_SIZE, NULL, 0);
|
||
|
if (IS_ERR_OR_NULL(minfo->pb_fshared)) {
|
||
|
err("failed to allocate buffer for FSHARED_REGION");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
minfo->total_size += minfo->pb_fshared->size;
|
||
|
|
||
|
#if !defined(ENABLE_DYNAMIC_MEM)
|
||
|
/* 3aa/isp internal DMA buffer */
|
||
|
minfo->pb_taaisp = CALL_PTR_MEMOP(mem, alloc, mem->default_ctx,
|
||
|
TAAISP_DMA_SIZE, NULL, 0);
|
||
|
if (IS_ERR_OR_NULL(minfo->pb_taaisp)) {
|
||
|
err("failed to allocate buffer for TAAISP_DMA");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
minfo->total_size += minfo->pb_taaisp->size;
|
||
|
|
||
|
info("[RSC] TAAISP_DMA memory size (aligned) : %08lx\n", TAAISP_DMA_SIZE);
|
||
|
|
||
|
/* ME/DRC buffer */
|
||
|
#if (MEDRC_DMA_SIZE > 0)
|
||
|
minfo->pb_medrc = CALL_PTR_MEMOP(mem, alloc, mem->default_ctx,
|
||
|
MEDRC_DMA_SIZE, NULL, 0);
|
||
|
if (IS_ERR_OR_NULL(minfo->pb_medrc)) {
|
||
|
err("failed to allocate buffer for ME_DRC");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
|
||
|
info("[RSC] ME_DRC memory size (aligned) : %08lx\n", MEDRC_DMA_SIZE);
|
||
|
|
||
|
minfo->total_size += minfo->pb_medrc->size;
|
||
|
#endif
|
||
|
|
||
|
#if defined(ENABLE_TNR)
|
||
|
/* TNR internal DMA buffer */
|
||
|
minfo->pb_tnr = CALL_PTR_MEMOP(mem, alloc, mem->default_ctx, tnr_size, NULL, 0);
|
||
|
if (IS_ERR_OR_NULL(minfo->pb_tnr)) {
|
||
|
err("failed to allocate buffer for TNR DMA");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
minfo->total_size += minfo->pb_tnr->size;
|
||
|
|
||
|
info("[RSC] TNR_DMA memory size: %08lx\n", tnr_size);
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#if defined (ENABLE_FD_SW)
|
||
|
minfo->pb_lhfd = CALL_PTR_MEMOP(mem, alloc, mem->default_ctx, LHFD_MAP_SIZE, NULL, 0);
|
||
|
if (IS_ERR_OR_NULL(minfo->pb_lhfd)) {
|
||
|
err("failed to allocate buffer for LHFD_MAP");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
minfo->total_size += minfo->pb_lhfd->size;
|
||
|
#endif
|
||
|
|
||
|
#if defined (ENABLE_VRA)
|
||
|
minfo->pb_vra = CALL_PTR_MEMOP(mem, alloc, mem->default_ctx, VRA_DMA_SIZE, NULL, 0);
|
||
|
if (IS_ERR_OR_NULL(minfo->pb_vra)) {
|
||
|
err("failed to allocate buffer for VRA");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
minfo->total_size += minfo->pb_vra->size;
|
||
|
#endif
|
||
|
|
||
|
#if defined (ENABLE_DNR_IN_MCSC)
|
||
|
minfo->pb_mcsc_dnr = CALL_PTR_MEMOP(mem, alloc, mem->default_ctx, MCSC_DNR_DMA_SIZE, NULL, 0);
|
||
|
if (IS_ERR_OR_NULL(minfo->pb_mcsc_dnr)) {
|
||
|
err("failed to allocate buffer for MCSC DNR");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
minfo->total_size += minfo->pb_mcsc_dnr->size;
|
||
|
#endif
|
||
|
|
||
|
#if defined (ENABLE_ODC)
|
||
|
tpu_size += (SIZE_ODC_INTERNAL_BUF * NUM_ODC_INTERNAL_BUF);
|
||
|
#endif
|
||
|
#if defined (ENABLE_VDIS)
|
||
|
tpu_size += (SIZE_DIS_INTERNAL_BUF * NUM_DIS_INTERNAL_BUF);
|
||
|
#endif
|
||
|
#if defined (ENABLE_DNR_IN_TPU)
|
||
|
tpu_size += (SIZE_DNR_INTERNAL_BUF * NUM_DNR_INTERNAL_BUF);
|
||
|
#endif
|
||
|
if (tpu_size > 0) {
|
||
|
minfo->pb_tpu = CALL_PTR_MEMOP(mem, alloc, mem->default_ctx, tpu_size, NULL, 0);
|
||
|
if (IS_ERR_OR_NULL(minfo->pb_tpu)) {
|
||
|
err("failed to allocate buffer for TPU");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
minfo->total_size += minfo->pb_tpu->size;
|
||
|
}
|
||
|
|
||
|
probe_info("[RSC] Internal memory size (aligned) : %08lx\n", minfo->total_size);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int fimc_is_resourcemgr_initmem(struct fimc_is_resourcemgr *resourcemgr)
|
||
|
{
|
||
|
struct fimc_is_minfo *minfo = NULL;
|
||
|
int ret = 0;
|
||
|
int i;
|
||
|
|
||
|
probe_info("fimc_is_init_mem - ION\n");
|
||
|
|
||
|
ret = fimc_is_resourcemgr_allocmem(resourcemgr);
|
||
|
if (ret) {
|
||
|
err("Couldn't alloc for FIMC-IS\n");
|
||
|
ret = -ENOMEM;
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
minfo = &resourcemgr->minfo;
|
||
|
/* set information */
|
||
|
resourcemgr->minfo.dvaddr = 0;
|
||
|
resourcemgr->minfo.kvaddr = 0;
|
||
|
|
||
|
resourcemgr->minfo.dvaddr_debug = CALL_BUFOP(minfo->pb_debug, dvaddr, minfo->pb_debug);
|
||
|
resourcemgr->minfo.kvaddr_debug = CALL_BUFOP(minfo->pb_debug, kvaddr, minfo->pb_debug);
|
||
|
resourcemgr->minfo.phaddr_debug = CALL_BUFOP(minfo->pb_debug, phaddr, minfo->pb_debug);
|
||
|
|
||
|
resourcemgr->minfo.dvaddr_event = CALL_BUFOP(minfo->pb_event, dvaddr, minfo->pb_event);
|
||
|
resourcemgr->minfo.kvaddr_event = CALL_BUFOP(minfo->pb_event, kvaddr, minfo->pb_event);
|
||
|
resourcemgr->minfo.phaddr_event = CALL_BUFOP(minfo->pb_event, phaddr, minfo->pb_event);
|
||
|
|
||
|
resourcemgr->minfo.dvaddr_fshared = CALL_BUFOP(minfo->pb_fshared, dvaddr, minfo->pb_fshared);
|
||
|
resourcemgr->minfo.kvaddr_fshared = CALL_BUFOP(minfo->pb_fshared, kvaddr, minfo->pb_fshared);
|
||
|
|
||
|
resourcemgr->minfo.dvaddr_region = CALL_BUFOP(minfo->pb_pregion, dvaddr, minfo->pb_pregion);
|
||
|
resourcemgr->minfo.kvaddr_region = CALL_BUFOP(minfo->pb_pregion, kvaddr, minfo->pb_pregion);
|
||
|
|
||
|
#if defined(ENABLE_FD_SW)
|
||
|
resourcemgr->minfo.dvaddr_lhfd = CALL_BUFOP(minfo->pb_lhfd, dvaddr, minfo->pb_lhfd);
|
||
|
resourcemgr->minfo.kvaddr_lhfd = CALL_BUFOP(minfo->pb_lhfd, kvaddr, minfo->pb_lhfd);
|
||
|
#else
|
||
|
resourcemgr->minfo.dvaddr_lhfd = 0;
|
||
|
resourcemgr->minfo.kvaddr_lhfd = 0;
|
||
|
#endif
|
||
|
|
||
|
#if defined(ENABLE_VRA)
|
||
|
resourcemgr->minfo.dvaddr_vra = CALL_BUFOP(minfo->pb_vra, dvaddr, minfo->pb_vra);
|
||
|
resourcemgr->minfo.kvaddr_vra = CALL_BUFOP(minfo->pb_vra, kvaddr, minfo->pb_vra);
|
||
|
#else
|
||
|
resourcemgr->minfo.dvaddr_vra = 0;
|
||
|
resourcemgr->minfo.kvaddr_vra = 0;
|
||
|
#endif
|
||
|
|
||
|
#if defined(ENABLE_DNR_IN_MCSC)
|
||
|
resourcemgr->minfo.dvaddr_mcsc_dnr = CALL_BUFOP(minfo->pb_mcsc_dnr, dvaddr, minfo->pb_mcsc_dnr);
|
||
|
resourcemgr->minfo.kvaddr_mcsc_dnr = CALL_BUFOP(minfo->pb_mcsc_dnr, kvaddr, minfo->pb_mcsc_dnr);
|
||
|
#else
|
||
|
resourcemgr->minfo.dvaddr_mcsc_dnr = 0;
|
||
|
resourcemgr->minfo.kvaddr_mcsc_dnr = 0;
|
||
|
#endif
|
||
|
|
||
|
#if defined(ENABLE_ODC) || defined(ENABLE_VDIS) || defined(ENABLE_DNR_IN_TPU)
|
||
|
resourcemgr->minfo.dvaddr_tpu = CALL_BUFOP(minfo->pb_tpu, dvaddr, minfo->pb_tpu);
|
||
|
resourcemgr->minfo.kvaddr_tpu = CALL_BUFOP(minfo->pb_tpu, kvaddr, minfo->pb_tpu);
|
||
|
#else
|
||
|
resourcemgr->minfo.dvaddr_tpu = 0;
|
||
|
resourcemgr->minfo.kvaddr_tpu = 0;
|
||
|
#endif
|
||
|
resourcemgr->minfo.kvaddr_debug_cnt = resourcemgr->minfo.kvaddr_debug
|
||
|
+ DEBUG_REGION_SIZE;
|
||
|
resourcemgr->minfo.kvaddr_event_cnt = resourcemgr->minfo.kvaddr_event
|
||
|
+ EVENT_REGION_SIZE;
|
||
|
resourcemgr->minfo.kvaddr_setfile = CALL_BUFOP(minfo->pb_setfile, kvaddr, minfo->pb_setfile);
|
||
|
|
||
|
for (i = 0; i < SENSOR_POSITION_MAX; i++)
|
||
|
resourcemgr->minfo.kvaddr_cal[i] =
|
||
|
CALL_BUFOP(minfo->pb_cal[i], kvaddr, minfo->pb_cal[i]);
|
||
|
|
||
|
probe_info("[RSC] Kernel virtual for library: %08lx\n", resourcemgr->minfo.kvaddr);
|
||
|
probe_info("[RSC] Kernel virtual for debug: %08lx\n", resourcemgr->minfo.kvaddr_debug);
|
||
|
probe_info("[RSC] fimc_is_init_mem done\n");
|
||
|
p_err:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
#ifdef ENABLE_DYNAMIC_MEM
|
||
|
static int fimc_is_resourcemgr_alloc_dynamic_mem(struct fimc_is_resourcemgr *resourcemgr)
|
||
|
{
|
||
|
struct fimc_is_mem *mem = &resourcemgr->mem;
|
||
|
struct fimc_is_minfo *minfo = &resourcemgr->minfo;
|
||
|
#if defined (ENABLE_TNR)
|
||
|
size_t tnr_size = ((SIZE_TNR_IMAGE_BUF + SIZE_TNR_WEIGHT_BUF) * NUM_OF_TNR_BUF);
|
||
|
#endif
|
||
|
|
||
|
/* 3aa/isp internal DMA buffer */
|
||
|
minfo->pb_taaisp = CALL_PTR_MEMOP(mem, alloc, mem->default_ctx,
|
||
|
TAAISP_DMA_SIZE, NULL, 0);
|
||
|
if (IS_ERR_OR_NULL(minfo->pb_taaisp)) {
|
||
|
err("failed to allocate buffer for TAAISP_DMA memory");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
|
||
|
info("[RSC] TAAISP_DMA memory size (aligned) : %08lx\n", TAAISP_DMA_SIZE);
|
||
|
|
||
|
/* ME/DRC buffer */
|
||
|
#if (MEDRC_DMA_SIZE > 0)
|
||
|
minfo->pb_medrc = CALL_PTR_MEMOP(mem, alloc, mem->default_ctx,
|
||
|
MEDRC_DMA_SIZE, NULL, 0);
|
||
|
if (IS_ERR_OR_NULL(minfo->pb_medrc)) {
|
||
|
CALL_VOID_BUFOP(minfo->pb_taaisp, free, minfo->pb_taaisp);
|
||
|
err("failed to allocate buffer for ME_DRC");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
|
||
|
info("[RSC] ME_DRC memory size (aligned) : %08lx\n", MEDRC_DMA_SIZE);
|
||
|
#endif
|
||
|
|
||
|
#if defined(ENABLE_TNR)
|
||
|
/* TNR internal DMA buffer */
|
||
|
minfo->pb_tnr = CALL_PTR_MEMOP(mem, alloc, mem->default_ctx, tnr_size, NULL, 0);
|
||
|
if (IS_ERR_OR_NULL(minfo->pb_tnr)) {
|
||
|
CALL_VOID_BUFOP(minfo->pb_taaisp, free, minfo->pb_taaisp);
|
||
|
#if (MEDRC_DMA_SIZE > 0)
|
||
|
CALL_VOID_BUFOP(minfo->pb_medrc, free, minfo->pb_medrc);
|
||
|
#endif
|
||
|
err("failed to allocate buffer for TNR DMA");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
|
||
|
info("[RSC] TNR_DMA memory size: %08lx\n", tnr_size);
|
||
|
#endif
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int fimc_is_resourcemgr_init_dynamic_mem(struct fimc_is_resourcemgr *resourcemgr)
|
||
|
{
|
||
|
struct fimc_is_minfo *minfo = &resourcemgr->minfo;
|
||
|
int ret = 0;
|
||
|
unsigned long kva;
|
||
|
dma_addr_t dva;
|
||
|
|
||
|
probe_info("fimc_is_init_mem - ION\n");
|
||
|
|
||
|
ret = fimc_is_resourcemgr_alloc_dynamic_mem(resourcemgr);
|
||
|
if (ret) {
|
||
|
err("Couldn't alloc for FIMC-IS\n");
|
||
|
ret = -ENOMEM;
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
kva = CALL_BUFOP(minfo->pb_taaisp, kvaddr, minfo->pb_taaisp);
|
||
|
dva = CALL_BUFOP(minfo->pb_taaisp, dvaddr, minfo->pb_taaisp);
|
||
|
info("[RSC] TAAISP_DMA memory kva:0x%1x, dva: %pad\n", kva, &dva);
|
||
|
|
||
|
#if (MEDRC_DMA_SIZE > 0)
|
||
|
kva = CALL_BUFOP(minfo->pb_medrc, kvaddr, minfo->pb_medrc);
|
||
|
dva = CALL_BUFOP(minfo->pb_medrc, dvaddr, minfo->pb_medrc);
|
||
|
info("[RSC] ME_DRC memory kva:0x%1x, dva: %pad\n", kva, &dva);
|
||
|
#endif
|
||
|
|
||
|
#if defined(ENABLE_TNR)
|
||
|
kva = CALL_BUFOP(minfo->pb_tnr, kvaddr, minfo->pb_tnr);
|
||
|
dva = CALL_BUFOP(minfo->pb_tnr, dvaddr, minfo->pb_tnr);
|
||
|
info("[RSC] TNR_DMA memory kva:0x%1x, dva: %pad\n", kva, &dva);
|
||
|
#endif
|
||
|
|
||
|
info("[RSC] %s done\n", __func__);
|
||
|
|
||
|
p_err:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int fimc_is_resourcemgr_deinit_dynamic_mem(struct fimc_is_resourcemgr *resourcemgr)
|
||
|
{
|
||
|
struct fimc_is_minfo *minfo = &resourcemgr->minfo;
|
||
|
|
||
|
#if defined(ENABLE_TNR)
|
||
|
CALL_VOID_BUFOP(minfo->pb_tnr, free, minfo->pb_tnr);
|
||
|
#endif
|
||
|
#if (MEDRC_DMA_SIZE > 0)
|
||
|
CALL_VOID_BUFOP(minfo->pb_medrc, free, minfo->pb_medrc);
|
||
|
#endif
|
||
|
CALL_VOID_BUFOP(minfo->pb_taaisp, free, minfo->pb_taaisp);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
#endif /* #ifdef ENABLE_DYNAMIC_MEM */
|
||
|
|
||
|
#if defined(SECURE_CAMERA_FACE)
|
||
|
static int fimc_is_resourcemgr_alloc_secure_mem(struct fimc_is_resourcemgr *resourcemgr)
|
||
|
{
|
||
|
struct fimc_is_mem *mem = &resourcemgr->mem;
|
||
|
struct fimc_is_minfo *minfo = &resourcemgr->minfo;
|
||
|
|
||
|
/* 3aa/isp internal DMA buffer */
|
||
|
minfo->pb_taaisp_s = CALL_PTR_MEMOP(mem, alloc, mem->default_ctx,
|
||
|
TAAISP_DMA_SIZE, "camera_heap",
|
||
|
ION_FLAG_CACHED | ION_FLAG_PROTECTED);
|
||
|
if (IS_ERR_OR_NULL(minfo->pb_taaisp_s)) {
|
||
|
err("failed to allocate buffer for TAAISP_DMA_S");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
|
||
|
info("[RSC] TAAISP_DMA_S memory size (aligned) : %08lx\n", TAAISP_DMA_SIZE);
|
||
|
|
||
|
/* ME/DRC buffer */
|
||
|
#if (MEDRC_DMA_SIZE > 0)
|
||
|
minfo->pb_medrc_s = CALL_PTR_MEMOP(mem, alloc, mem->default_ctx,
|
||
|
MEDRC_DMA_SIZE, "secure_camera_heap",
|
||
|
ION_FLAG_CACHED | ION_FLAG_PROTECTED);
|
||
|
if (IS_ERR_OR_NULL(minfo->pb_medrc_s)) {
|
||
|
CALL_VOID_BUFOP(minfo->pb_taaisp_s, free, minfo->pb_taaisp_s);
|
||
|
err("failed to allocate buffer for ME_DRC_S");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
|
||
|
info("[RSC] ME_DRC_S memory size (aligned) : %08lx\n", MEDRC_DMA_SIZE);
|
||
|
#endif
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int fimc_is_resourcemgr_init_secure_mem(struct fimc_is_resourcemgr *resourcemgr)
|
||
|
{
|
||
|
struct fimc_is_core *core;
|
||
|
int ret = 0;
|
||
|
|
||
|
core = container_of(resourcemgr, struct fimc_is_core, resourcemgr);
|
||
|
FIMC_BUG(!core);
|
||
|
|
||
|
if (core->scenario != FIMC_IS_SCENARIO_SECURE)
|
||
|
return ret;
|
||
|
|
||
|
info("fimc_is_init_secure_mem - ION\n");
|
||
|
|
||
|
ret = fimc_is_resourcemgr_alloc_secure_mem(resourcemgr);
|
||
|
if (ret) {
|
||
|
err("Couldn't alloc for FIMC-IS\n");
|
||
|
ret = -ENOMEM;
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
info("[RSC] %s done\n", __func__);
|
||
|
p_err:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int fimc_is_resourcemgr_deinit_secure_mem(struct fimc_is_resourcemgr *resourcemgr)
|
||
|
{
|
||
|
struct fimc_is_minfo *minfo = &resourcemgr->minfo;
|
||
|
struct fimc_is_core *core;
|
||
|
int ret = 0;
|
||
|
|
||
|
core = container_of(resourcemgr, struct fimc_is_core, resourcemgr);
|
||
|
FIMC_BUG(!core);
|
||
|
|
||
|
if (minfo->pb_taaisp_s)
|
||
|
CALL_VOID_BUFOP(minfo->pb_taaisp_s, free, minfo->pb_taaisp_s);
|
||
|
if (minfo->pb_medrc_s)
|
||
|
CALL_VOID_BUFOP(minfo->pb_medrc_s, free, minfo->pb_medrc_s);
|
||
|
|
||
|
minfo->pb_taaisp_s = NULL;
|
||
|
minfo->pb_medrc_s = NULL;
|
||
|
|
||
|
info("[RSC] %s done\n", __func__);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static struct vm_struct fimc_is_lib_vm;
|
||
|
static struct vm_struct fimc_is_heap_vm;
|
||
|
static struct vm_struct fimc_is_heap_rta_vm;
|
||
|
#ifdef CONFIG_UH_RKP
|
||
|
static struct vm_struct fimc_lib_vm_for_rkp;
|
||
|
#endif
|
||
|
#if defined(RESERVED_MEM_IN_DT)
|
||
|
static int fimc_is_rmem_device_init(struct reserved_mem *rmem,
|
||
|
struct device *dev)
|
||
|
{
|
||
|
WARN(1, "%s() should never be called!", __func__);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void fimc_is_rmem_device_release(struct reserved_mem *rmem,
|
||
|
struct device *dev)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
static const struct reserved_mem_ops fimc_is_rmem_ops = {
|
||
|
.device_init = fimc_is_rmem_device_init,
|
||
|
.device_release = fimc_is_rmem_device_release,
|
||
|
};
|
||
|
|
||
|
static int __init fimc_is_reserved_mem_setup(struct reserved_mem *rmem)
|
||
|
{
|
||
|
const __be32 *prop;
|
||
|
u64 kbase;
|
||
|
int len;
|
||
|
#ifdef CONFIG_UH_RKP
|
||
|
u64 roundup_end_addr = 0;
|
||
|
rkp_dynamic_load_t rkp_dyn;
|
||
|
int ret;
|
||
|
#endif
|
||
|
|
||
|
prop = of_get_flat_dt_prop(rmem->fdt_node, "kernel_virt", &len);
|
||
|
if (!prop) {
|
||
|
pr_err("kernel_virt is not found in '%s' node\n", rmem->name);
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
if (len != dt_root_addr_cells * sizeof(__be32)) {
|
||
|
pr_err("invalid kernel_virt property in '%s' node.\n",
|
||
|
rmem->name);
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
kbase = dt_mem_next_cell(dt_root_addr_cells, &prop);
|
||
|
|
||
|
fimc_is_lib_vm.phys_addr = rmem->base;
|
||
|
fimc_is_lib_vm.addr = (void *)kbase;
|
||
|
fimc_is_lib_vm.size = LIB_SIZE + PAGE_SIZE;
|
||
|
|
||
|
BUG_ON(rmem->size < LIB_SIZE);
|
||
|
|
||
|
#ifdef CONFIG_UH_RKP
|
||
|
memcpy(&fimc_lib_vm_for_rkp, &fimc_is_lib_vm, sizeof(struct vm_struct));
|
||
|
|
||
|
roundup_end_addr = (u64)roundup((u64)fimc_is_lib_vm.addr + (u64)fimc_is_lib_vm.size, SECTION_SIZE);
|
||
|
fimc_lib_vm_for_rkp.addr = (void *)rounddown((u64)fimc_lib_vm_for_rkp.addr, SECTION_SIZE);
|
||
|
fimc_lib_vm_for_rkp.size = roundup_end_addr - (u64)fimc_lib_vm_for_rkp.addr;
|
||
|
|
||
|
rkp_dyn.binary_base = fimc_is_lib_vm.phys_addr;
|
||
|
rkp_dyn.binary_size = LIB_SIZE;
|
||
|
rkp_dyn.type = RKP_DYN_COMMAND_BREAKDOWN_BEFORE_INIT;
|
||
|
ret = uh_call(UH_APP_RKP, RKP_DYNAMIC_LOAD, RKP_DYN_COMMAND_BREAKDOWN_BEFORE_INIT,(u64)&rkp_dyn, 0, 0);
|
||
|
if (ret) {
|
||
|
err_lib("fail to break-before-init FIMC in EL2");
|
||
|
}
|
||
|
vm_area_add_early(&fimc_lib_vm_for_rkp);
|
||
|
#else
|
||
|
vm_area_add_early(&fimc_is_lib_vm);
|
||
|
#endif
|
||
|
|
||
|
probe_info("fimc-is library memory: 0x%llx\n", kbase);
|
||
|
|
||
|
fimc_is_heap_vm.addr = (void *)HEAP_START;
|
||
|
fimc_is_heap_vm.size = HEAP_SIZE + PAGE_SIZE;
|
||
|
|
||
|
vm_area_add_early(&fimc_is_heap_vm);
|
||
|
|
||
|
probe_info("fimc-is heap memory: 0x%lx\n", HEAP_START);
|
||
|
|
||
|
rmem->ops = &fimc_is_rmem_ops;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
RESERVEDMEM_OF_DECLARE(fimc_is_lib, "exynos,fimc_is_lib", fimc_is_reserved_mem_setup);
|
||
|
#else
|
||
|
static int __init fimc_is_lib_mem_alloc(char *str)
|
||
|
{
|
||
|
ulong addr = 0;
|
||
|
#ifdef CONFIG_UH_RKP
|
||
|
u64 roundup_end_addr = 0;
|
||
|
rkp_dynamic_load_t rkp_dyn;
|
||
|
int ret;
|
||
|
#endif
|
||
|
|
||
|
if (kstrtoul(str, 0, (ulong *)&addr) || !addr) {
|
||
|
probe_warn("invalid fimc-is library memory address, use default");
|
||
|
addr = __LIB_START;
|
||
|
}
|
||
|
|
||
|
if (addr != __LIB_START)
|
||
|
probe_warn("use different address [reserve-fimc=0x%lx default:0x%lx]",
|
||
|
addr, __LIB_START);
|
||
|
|
||
|
fimc_is_lib_vm.phys_addr = memblock_alloc(LIB_SIZE, SZ_2M);
|
||
|
fimc_is_lib_vm.addr = (void *)addr;
|
||
|
fimc_is_lib_vm.size = LIB_SIZE + PAGE_SIZE;
|
||
|
#ifdef CONFIG_UH_RKP
|
||
|
memcpy(&fimc_lib_vm_for_rkp, &fimc_is_lib_vm, sizeof(struct vm_struct));
|
||
|
|
||
|
roundup_end_addr = (u64)roundup((u64)fimc_is_lib_vm.addr + (u64)fimc_is_lib_vm.size, SECTION_SIZE);
|
||
|
fimc_lib_vm_for_rkp.addr = (void *)rounddown((u64)fimc_lib_vm_for_rkp.addr, SECTION_SIZE);
|
||
|
fimc_lib_vm_for_rkp.size = roundup_end_addr - (u64)fimc_lib_vm_for_rkp.addr;
|
||
|
|
||
|
rkp_dyn.binary_base = fimc_is_lib_vm.phys_addr;
|
||
|
rkp_dyn.binary_size = LIB_SIZE;
|
||
|
rkp_dyn.type = RKP_DYN_COMMAND_BREAKDOWN_BEFORE_INIT;
|
||
|
ret = uh_call(UH_APP_RKP, RKP_DYNAMIC_LOAD, RKP_DYN_COMMAND_BREAKDOWN_BEFORE_INIT, (u64)&rkp_dyn, 0, 0);
|
||
|
if (ret) {
|
||
|
err_lib("fail to break-before-init FIMC in EL2");
|
||
|
}
|
||
|
vm_area_add_early(&fimc_lib_vm_for_rkp);
|
||
|
// vm_area_add_early(&fimc_is_lib_vm);
|
||
|
#else
|
||
|
vm_area_add_early(&fimc_is_lib_vm);
|
||
|
#endif
|
||
|
|
||
|
probe_info("fimc-is library memory: 0x%lx\n", addr);
|
||
|
|
||
|
fimc_is_heap_vm.addr = (void *)HEAP_START;
|
||
|
fimc_is_heap_vm.size = HEAP_SIZE + PAGE_SIZE;
|
||
|
|
||
|
vm_area_add_early(&fimc_is_heap_vm);
|
||
|
|
||
|
probe_info("fimc-is heap DDK memory: 0x%lx\n", HEAP_START);
|
||
|
|
||
|
fimc_is_heap_rta_vm.addr = (void *)HEAP_RTA_START;
|
||
|
fimc_is_heap_rta_vm.size = HEAP_RTA_SIZE + PAGE_SIZE;
|
||
|
|
||
|
vm_area_add_early(&fimc_is_heap_rta_vm);
|
||
|
|
||
|
probe_info("fimc-is heap RTA memory: 0x%lx\n", HEAP_RTA_START);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
__setup("reserve-fimc=", fimc_is_lib_mem_alloc);
|
||
|
#endif
|
||
|
|
||
|
static int __init fimc_is_lib_mem_map(void)
|
||
|
{
|
||
|
int page_size, i;
|
||
|
struct page *page;
|
||
|
struct page **pages;
|
||
|
pgprot_t prot;
|
||
|
|
||
|
#ifdef CONFIG_UH_RKP
|
||
|
prot = PAGE_KERNEL_RKP_RO;
|
||
|
#else
|
||
|
prot = PAGE_KERNEL;
|
||
|
#endif
|
||
|
|
||
|
if (!fimc_is_lib_vm.phys_addr) {
|
||
|
probe_err("There is no reserve-fimc= at bootargs.");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
|
||
|
page_size = fimc_is_lib_vm.size / PAGE_SIZE;
|
||
|
pages = kzalloc(sizeof(struct page*) * page_size, GFP_KERNEL);
|
||
|
page = phys_to_page(fimc_is_lib_vm.phys_addr);
|
||
|
|
||
|
for (i = 0; i < page_size; i++)
|
||
|
pages[i] = page++;
|
||
|
|
||
|
if (map_vm_area(&fimc_is_lib_vm, prot, pages)) {
|
||
|
probe_err("failed to mapping between virt and phys for binary");
|
||
|
vunmap(fimc_is_lib_vm.addr);
|
||
|
kfree(pages);
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
|
||
|
kfree(pages);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int __init fimc_is_heap_mem_map(struct fimc_is_resourcemgr *resourcemgr,
|
||
|
struct vm_struct *vm, int heap_size)
|
||
|
{
|
||
|
struct fimc_is_mem *mem = &resourcemgr->mem;
|
||
|
struct fimc_is_priv_buf *pb;
|
||
|
struct scatterlist *sg;
|
||
|
struct sg_table *table;
|
||
|
int i, j;
|
||
|
int npages = vm->size / PAGE_SIZE;
|
||
|
struct page **pages = vmalloc(sizeof(struct page *) * npages);
|
||
|
struct page **tmp = pages;
|
||
|
|
||
|
pb = CALL_PTR_MEMOP(mem, alloc, mem->default_ctx, heap_size, NULL, 0);
|
||
|
if (IS_ERR_OR_NULL(pb)) {
|
||
|
err("failed to allocate buffer for HEAP");
|
||
|
vfree(pages);
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
|
||
|
table = pb->sgt;
|
||
|
|
||
|
for_each_sg(table->sgl, sg, table->nents, i) {
|
||
|
int npages_this_entry = PAGE_ALIGN(sg->length) / PAGE_SIZE;
|
||
|
struct page *page = sg_page(sg);
|
||
|
|
||
|
BUG_ON(i >= npages);
|
||
|
|
||
|
for (j = 0; j < npages_this_entry; j++)
|
||
|
*(tmp++) = page++;
|
||
|
}
|
||
|
|
||
|
if (map_vm_area(vm, PAGE_KERNEL, pages)) {
|
||
|
probe_err("failed to mapping between virt and phys for binary");
|
||
|
vunmap(vm->addr);
|
||
|
vfree(pages);
|
||
|
CALL_VOID_BUFOP(pb, free, pb);
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
|
||
|
vfree(pages);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
#endif /* #ifdef ENABLE_IS_CORE */
|
||
|
|
||
|
static int fimc_is_tmu_notifier(struct notifier_block *nb,
|
||
|
unsigned long state, void *data)
|
||
|
{
|
||
|
#ifdef CONFIG_EXYNOS_THERMAL
|
||
|
int ret = 0, fps = 0;
|
||
|
struct fimc_is_resourcemgr *resourcemgr;
|
||
|
#if IS_ENABLED(CONFIG_EXYNOS_SNAPSHOT_THERMAL) || IS_ENABLED(CONFIG_DEBUG_SNAPSHOT_THERMAL)
|
||
|
char *cooling_device_name = "ISP";
|
||
|
#endif
|
||
|
resourcemgr = container_of(nb, struct fimc_is_resourcemgr, tmu_notifier);
|
||
|
|
||
|
switch (state) {
|
||
|
case ISP_NORMAL:
|
||
|
resourcemgr->tmu_state = ISP_NORMAL;
|
||
|
resourcemgr->limited_fps = 0;
|
||
|
break;
|
||
|
case ISP_COLD:
|
||
|
resourcemgr->tmu_state = ISP_COLD;
|
||
|
resourcemgr->limited_fps = 0;
|
||
|
break;
|
||
|
case ISP_THROTTLING:
|
||
|
resourcemgr->tmu_state = ISP_THROTTLING;
|
||
|
fps = isp_cooling_get_fps(0, *(unsigned long *)data);
|
||
|
|
||
|
/* The FPS can be defined to any specific value. */
|
||
|
if (fps >= 60) {
|
||
|
resourcemgr->limited_fps = 0;
|
||
|
warn("[RSC] THROTTLING : Unlimited FPS");
|
||
|
} else {
|
||
|
resourcemgr->limited_fps = fps;
|
||
|
warn("[RSC] THROTTLING : Limited %dFPS", fps);
|
||
|
}
|
||
|
break;
|
||
|
case ISP_TRIPPING:
|
||
|
resourcemgr->tmu_state = ISP_TRIPPING;
|
||
|
resourcemgr->limited_fps = 5;
|
||
|
warn("[RSC] TRIPPING : Limited 5FPS");
|
||
|
break;
|
||
|
default:
|
||
|
err("[RSC] invalid tmu state(%ld)", state);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#if IS_ENABLED(CONFIG_EXYNOS_SNAPSHOT_THERMAL)
|
||
|
exynos_ss_thermal(NULL, 0, cooling_device_name, resourcemgr->limited_fps);
|
||
|
#elif IS_ENABLED(CONFIG_DEBUG_SNAPSHOT_THERMAL)
|
||
|
dbg_snapshot_thermal(NULL, 0, cooling_device_name, resourcemgr->limited_fps);
|
||
|
#endif
|
||
|
|
||
|
return ret;
|
||
|
#else
|
||
|
|
||
|
return 0;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#ifdef CONFIG_EXYNOS_BUSMONITOR
|
||
|
static int due_to_fimc_is(const char *desc)
|
||
|
{
|
||
|
if (desc && (strstr((char *)desc, "CAM")
|
||
|
|| strstr((char *)desc, "ISP")))
|
||
|
return 1;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int fimc_is_bm_notifier(struct notifier_block *nb,
|
||
|
unsigned long state, void *data)
|
||
|
{
|
||
|
int i;
|
||
|
struct fimc_is_core *core;
|
||
|
struct fimc_is_resourcemgr *resourcemgr;
|
||
|
struct busmon_notifier *busmon;
|
||
|
|
||
|
resourcemgr = container_of(nb, struct fimc_is_resourcemgr, bm_notifier);
|
||
|
core = container_of(resourcemgr, struct fimc_is_core, resourcemgr);
|
||
|
busmon = (struct busmon_notifier *)data;
|
||
|
|
||
|
if (!busmon)
|
||
|
return 0;
|
||
|
|
||
|
if (due_to_fimc_is(busmon->init_desc)
|
||
|
|| due_to_fimc_is(busmon->target_desc)
|
||
|
|| due_to_fimc_is(busmon->masterip_desc)) {
|
||
|
info("1. NOC info.\n");
|
||
|
info("%s: init description : %s\n", __func__, busmon->init_desc);
|
||
|
info("%s: target descrition: %s\n", __func__, busmon->target_desc);
|
||
|
info("%s: user description : %s\n", __func__, busmon->masterip_desc);
|
||
|
info("%s: user id : %u\n", __func__, busmon->masterip_idx);
|
||
|
info("%s: target address : %lx\n",__func__, busmon->target_addr);
|
||
|
|
||
|
for (i = 0; i < FIMC_IS_STREAM_COUNT; ++i) {
|
||
|
if (!test_bit(FIMC_IS_ISCHAIN_POWER_ON, &core->ischain[i].state))
|
||
|
continue;
|
||
|
|
||
|
info("2. FW log dump\n");
|
||
|
fimc_is_hw_logdump(&core->interface);
|
||
|
|
||
|
info("3. Clock info.\n");
|
||
|
schedule_work(&core->wq_data_print_clk);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
#endif /* CONFIG_EXYNOS_BUSMONITOR */
|
||
|
|
||
|
#ifdef ENABLE_FW_SHARE_DUMP
|
||
|
static int fimc_is_fw_share_dump(void)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
u8 *buf;
|
||
|
struct fimc_is_core *core = NULL;
|
||
|
struct fimc_is_resourcemgr *resourcemgr;
|
||
|
|
||
|
core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
|
||
|
if (!core)
|
||
|
goto p_err;
|
||
|
|
||
|
resourcemgr = &core->resourcemgr;
|
||
|
buf = (u8 *)resourcemgr->fw_share_dump_buf;
|
||
|
|
||
|
/* dump share region in fw area */
|
||
|
if (IS_ERR_OR_NULL(buf)) {
|
||
|
err("%s: fail to alloc", __func__);
|
||
|
ret = -ENOMEM;
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
/* sync with fw for memory */
|
||
|
vb2_ion_sync_for_cpu(resourcemgr->minfo.fw_cookie, 0,
|
||
|
SHARED_OFFSET, DMA_BIDIRECTIONAL);
|
||
|
|
||
|
memcpy(buf, (u8 *)resourcemgr->minfo.kvaddr_fshared, SHARED_SIZE);
|
||
|
|
||
|
info("%s: dumped ramdump addr(virt/phys/size): (%p/%p/0x%X)", __func__, buf,
|
||
|
(void *)virt_to_phys(buf), SHARED_SIZE);
|
||
|
p_err:
|
||
|
return ret;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef ENABLE_KERNEL_LOG_DUMP
|
||
|
int fimc_is_kernel_log_dump(bool overwrite)
|
||
|
{
|
||
|
static int dumped = 0;
|
||
|
struct fimc_is_core *core;
|
||
|
struct fimc_is_resourcemgr *resourcemgr;
|
||
|
void *log_kernel = NULL;
|
||
|
unsigned long long when;
|
||
|
unsigned long usec;
|
||
|
|
||
|
core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
|
||
|
if (!core)
|
||
|
return -EINVAL;
|
||
|
|
||
|
resourcemgr = &core->resourcemgr;
|
||
|
|
||
|
if (dumped && !overwrite) {
|
||
|
when = resourcemgr->kernel_log_time;
|
||
|
usec = do_div(when, NSEC_PER_SEC) / NSEC_PER_USEC;
|
||
|
info("kernel log was saved already at [%5lu.%06lu]\n",
|
||
|
(unsigned long)when, usec);
|
||
|
|
||
|
return -ENOSPC;
|
||
|
}
|
||
|
|
||
|
#if IS_ENABLED(CONFIG_EXYNOS_SNAPSHOT)
|
||
|
log_kernel = (void *)exynos_ss_get_item_vaddr("log_kernel");
|
||
|
#elif IS_ENABLED(CONFIG_DEBUG_SNAPSHOT)
|
||
|
log_kernel = (void *)dbg_snapshot_get_item_vaddr("log_kernel");
|
||
|
#endif
|
||
|
if (!log_kernel)
|
||
|
return -EINVAL;
|
||
|
|
||
|
if (resourcemgr->kernel_log_buf) {
|
||
|
resourcemgr->kernel_log_time = local_clock();
|
||
|
|
||
|
info("kernel log saved to %p(%p) from %p\n",
|
||
|
resourcemgr->kernel_log_buf,
|
||
|
(void *)virt_to_phys(resourcemgr->kernel_log_buf),
|
||
|
log_kernel);
|
||
|
#if IS_ENABLED(CONFIG_EXYNOS_SNAPSHOT)
|
||
|
memcpy(resourcemgr->kernel_log_buf, log_kernel,
|
||
|
exynos_ss_get_item_size("log_kernel"));
|
||
|
#elif IS_ENABLED(CONFIG_DEBUG_SNAPSHOT)
|
||
|
memcpy(resourcemgr->kernel_log_buf, log_kernel,
|
||
|
dbg_snapshot_get_item_size("log_kernel"));
|
||
|
#endif
|
||
|
|
||
|
dumped = 1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
int fimc_is_resource_dump(void)
|
||
|
{
|
||
|
struct fimc_is_core *core = NULL;
|
||
|
struct fimc_is_group *group;
|
||
|
struct fimc_is_subdev *subdev;
|
||
|
struct fimc_is_framemgr *framemgr;
|
||
|
struct fimc_is_groupmgr *groupmgr;
|
||
|
struct fimc_is_device_ischain *device = NULL;
|
||
|
struct fimc_is_device_csi *csi;
|
||
|
int i, j, vc;
|
||
|
|
||
|
core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
|
||
|
if (!core)
|
||
|
goto exit;
|
||
|
|
||
|
info("### %s dump start ###\n", __func__);
|
||
|
|
||
|
groupmgr = &core->groupmgr;
|
||
|
|
||
|
/* dump per core */
|
||
|
for (i = 0; i < FIMC_IS_STREAM_COUNT; ++i) {
|
||
|
device = &core->ischain[i];
|
||
|
if (!test_bit(FIMC_IS_ISCHAIN_OPEN_STREAM, &device->state))
|
||
|
continue;
|
||
|
|
||
|
if (test_bit(FIMC_IS_ISCHAIN_CLOSING, &device->state))
|
||
|
continue;
|
||
|
|
||
|
/* clock & gpio dump */
|
||
|
schedule_work(&core->wq_data_print_clk);
|
||
|
#ifdef ENABLE_IS_CORE
|
||
|
/* fw log, mcuctl dump */
|
||
|
fimc_is_hw_logdump(&core->interface);
|
||
|
fimc_is_hw_regdump(&core->interface);
|
||
|
#else
|
||
|
/* ddk log dump */
|
||
|
fimc_is_lib_logdump();
|
||
|
fimc_is_hardware_clk_gate_dump(&core->hardware);
|
||
|
fimc_is_hardware_sfr_dump(&core->hardware, HW_SLOT_MAX, false);
|
||
|
#endif
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* dump per ischain */
|
||
|
for (i = 0; i < FIMC_IS_STREAM_COUNT; ++i) {
|
||
|
device = &core->ischain[i];
|
||
|
if (!test_bit(FIMC_IS_ISCHAIN_OPEN_STREAM, &device->state))
|
||
|
continue;
|
||
|
|
||
|
if (test_bit(FIMC_IS_ISCHAIN_CLOSING, &device->state))
|
||
|
continue;
|
||
|
|
||
|
if (device->sensor && !test_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state)) {
|
||
|
csi = (struct fimc_is_device_csi *)v4l2_get_subdevdata(device->sensor->subdev_csi);
|
||
|
if (csi) {
|
||
|
csi_hw_dump(csi->base_reg);
|
||
|
csi_hw_phy_dump(csi->phy_reg, csi->instance);
|
||
|
for (vc = CSI_VIRTUAL_CH_0; vc < CSI_VIRTUAL_CH_MAX; vc++) {
|
||
|
csi_hw_vcdma_dump(csi->vc_reg[csi->scm][vc]);
|
||
|
csi_hw_vcdma_cmn_dump(csi->cmn_reg[csi->scm][vc]);
|
||
|
}
|
||
|
csi_hw_common_dma_dump(csi->csi_dma->base_reg);
|
||
|
#if defined(ENABLE_PDP_STAT_DMA)
|
||
|
csi_hw_common_dma_dump(csi->csi_dma->base_reg_stat);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* dump all framemgr */
|
||
|
group = groupmgr->leader[i];
|
||
|
while (group) {
|
||
|
if (!test_bit(FIMC_IS_GROUP_OPEN, &group->state))
|
||
|
break;
|
||
|
|
||
|
for (j = 0; j < ENTRY_END; j++) {
|
||
|
subdev = group->subdev[j];
|
||
|
if (subdev && test_bit(FIMC_IS_SUBDEV_START, &subdev->state)) {
|
||
|
framemgr = GET_SUBDEV_FRAMEMGR(subdev);
|
||
|
if (framemgr) {
|
||
|
unsigned long flags;
|
||
|
|
||
|
mserr(" dump framemgr..", subdev, subdev);
|
||
|
framemgr_e_barrier_irqs(framemgr, 0, flags);
|
||
|
frame_manager_print_queues(framemgr);
|
||
|
framemgr_x_barrier_irqr(framemgr, 0, flags);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
group = group->next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
info("### %s dump end ###\n", __func__);
|
||
|
|
||
|
exit:
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#ifdef ENABLE_PANIC_HANDLER
|
||
|
static int fimc_is_panic_handler(struct notifier_block *nb, ulong l,
|
||
|
void *buf)
|
||
|
{
|
||
|
#if !defined(ENABLE_IS_CORE)
|
||
|
fimc_is_resource_dump();
|
||
|
#endif
|
||
|
#ifdef ENABLE_FW_SHARE_DUMP
|
||
|
/* dump share area in fw region */
|
||
|
fimc_is_fw_share_dump();
|
||
|
#endif
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static struct notifier_block notify_panic_block = {
|
||
|
.notifier_call = fimc_is_panic_handler,
|
||
|
};
|
||
|
#endif
|
||
|
|
||
|
#if defined(ENABLE_REBOOT_HANDLER) && !defined(ENABLE_IS_CORE)
|
||
|
static int fimc_is_reboot_handler(struct notifier_block *nb, ulong l,
|
||
|
void *buf)
|
||
|
{
|
||
|
struct fimc_is_core *core = NULL;
|
||
|
|
||
|
info("%s enter\n", __func__);
|
||
|
|
||
|
core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
|
||
|
if (core)
|
||
|
fimc_is_cleanup(core);
|
||
|
|
||
|
info("%s exit\n", __func__);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static struct notifier_block notify_reboot_block = {
|
||
|
.notifier_call = fimc_is_reboot_handler,
|
||
|
};
|
||
|
#endif
|
||
|
|
||
|
int fimc_is_resourcemgr_probe(struct fimc_is_resourcemgr *resourcemgr,
|
||
|
void *private_data, struct platform_device *pdev)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
struct device_node *np;
|
||
|
|
||
|
FIMC_BUG(!resourcemgr);
|
||
|
FIMC_BUG(!private_data);
|
||
|
|
||
|
np = pdev->dev.of_node;
|
||
|
resourcemgr->private_data = private_data;
|
||
|
|
||
|
clear_bit(FIMC_IS_RM_COM_POWER_ON, &resourcemgr->state);
|
||
|
clear_bit(FIMC_IS_RM_SS0_POWER_ON, &resourcemgr->state);
|
||
|
clear_bit(FIMC_IS_RM_SS1_POWER_ON, &resourcemgr->state);
|
||
|
clear_bit(FIMC_IS_RM_SS2_POWER_ON, &resourcemgr->state);
|
||
|
clear_bit(FIMC_IS_RM_SS3_POWER_ON, &resourcemgr->state);
|
||
|
clear_bit(FIMC_IS_RM_SS4_POWER_ON, &resourcemgr->state);
|
||
|
clear_bit(FIMC_IS_RM_SS5_POWER_ON, &resourcemgr->state);
|
||
|
clear_bit(FIMC_IS_RM_ISC_POWER_ON, &resourcemgr->state);
|
||
|
clear_bit(FIMC_IS_RM_POWER_ON, &resourcemgr->state);
|
||
|
atomic_set(&resourcemgr->rsccount, 0);
|
||
|
atomic_set(&resourcemgr->qos_refcount, 0);
|
||
|
atomic_set(&resourcemgr->resource_sensor0.rsccount, 0);
|
||
|
atomic_set(&resourcemgr->resource_sensor1.rsccount, 0);
|
||
|
atomic_set(&resourcemgr->resource_sensor2.rsccount, 0);
|
||
|
atomic_set(&resourcemgr->resource_sensor3.rsccount, 0);
|
||
|
atomic_set(&resourcemgr->resource_ischain.rsccount, 0);
|
||
|
atomic_set(&resourcemgr->resource_preproc.rsccount, 0);
|
||
|
|
||
|
resourcemgr->cluster0 = 0;
|
||
|
resourcemgr->cluster1 = 0;
|
||
|
resourcemgr->hal_version = IS_HAL_VER_1_0;
|
||
|
|
||
|
/* rsc mutex init */
|
||
|
mutex_init(&resourcemgr->rsc_lock);
|
||
|
mutex_init(&resourcemgr->sysreg_lock);
|
||
|
|
||
|
/* temperature monitor unit */
|
||
|
resourcemgr->tmu_notifier.notifier_call = fimc_is_tmu_notifier;
|
||
|
resourcemgr->tmu_notifier.priority = 0;
|
||
|
resourcemgr->tmu_state = ISP_NORMAL;
|
||
|
resourcemgr->limited_fps = 0;
|
||
|
|
||
|
/* bus monitor unit */
|
||
|
|
||
|
#ifdef CONFIG_EXYNOS_BUSMONITOR
|
||
|
resourcemgr->bm_notifier.notifier_call = fimc_is_bm_notifier;
|
||
|
resourcemgr->bm_notifier.priority = 0;
|
||
|
|
||
|
busmon_notifier_chain_register(&resourcemgr->bm_notifier);
|
||
|
#endif
|
||
|
|
||
|
ret = exynos_tmu_isp_add_notifier(&resourcemgr->tmu_notifier);
|
||
|
if (ret) {
|
||
|
probe_err("exynos_tmu_isp_add_notifier is fail(%d)", ret);
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
#ifdef ENABLE_RESERVED_MEM
|
||
|
ret = fimc_is_resourcemgr_initmem(resourcemgr);
|
||
|
if (ret) {
|
||
|
probe_err("fimc_is_resourcemgr_initmem is fail(%d)", ret);
|
||
|
goto p_err;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
ret = fimc_is_lib_mem_map();
|
||
|
if (ret) {
|
||
|
probe_err("fimc_is_lib_mem_map is fail(%d)", ret);
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
ret = fimc_is_heap_mem_map(resourcemgr, &fimc_is_heap_vm, HEAP_SIZE);
|
||
|
if (ret) {
|
||
|
probe_err("fimc_is_heap_mem_map for HEAP_DDK is fail(%d)", ret);
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
ret = fimc_is_heap_mem_map(resourcemgr, &fimc_is_heap_rta_vm, HEAP_RTA_SIZE);
|
||
|
if (ret) {
|
||
|
probe_err("fimc_is_heap_mem_map for HEAP_RTA is fail(%d)", ret);
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
#ifdef ENABLE_DVFS
|
||
|
/* dvfs controller init */
|
||
|
ret = fimc_is_dvfs_init(resourcemgr);
|
||
|
if (ret) {
|
||
|
probe_err("%s: fimc_is_dvfs_init failed!\n", __func__);
|
||
|
goto p_err;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef ENABLE_PANIC_HANDLER
|
||
|
atomic_notifier_chain_register(&panic_notifier_list, ¬ify_panic_block);
|
||
|
#endif
|
||
|
#if defined(ENABLE_REBOOT_HANDLER) && !defined(ENABLE_IS_CORE)
|
||
|
register_reboot_notifier(¬ify_reboot_block);
|
||
|
#endif
|
||
|
#ifdef ENABLE_SHARED_METADATA
|
||
|
spin_lock_init(&resourcemgr->shared_meta_lock);
|
||
|
#endif
|
||
|
#ifdef ENABLE_FW_SHARE_DUMP
|
||
|
/* to dump share region in fw area */
|
||
|
resourcemgr->fw_share_dump_buf = (ulong)kzalloc(SHARED_SIZE, GFP_KERNEL);
|
||
|
#endif
|
||
|
#ifdef CONFIG_CMU_EWF
|
||
|
get_cmuewf_index(np, &idx_ewf);
|
||
|
#endif
|
||
|
|
||
|
#ifdef ENABLE_KERNEL_LOG_DUMP
|
||
|
#if IS_ENABLED(CONFIG_EXYNOS_SNAPSHOT)
|
||
|
resourcemgr->kernel_log_buf = kzalloc(exynos_ss_get_item_size("log_kernel"),
|
||
|
GFP_KERNEL);
|
||
|
#elif IS_ENABLED(CONFIG_DEBUG_SNAPSHOT)
|
||
|
resourcemgr->kernel_log_buf = kzalloc(dbg_snapshot_get_item_size("log_kernel"),
|
||
|
GFP_KERNEL);
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
mutex_init(&resourcemgr->global_param.lock);
|
||
|
resourcemgr->global_param.video_mode = 0;
|
||
|
resourcemgr->global_param.state = 0;
|
||
|
|
||
|
p_err:
|
||
|
probe_info("[RSC] %s(%d)\n", __func__, ret);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int fimc_is_resource_open(struct fimc_is_resourcemgr *resourcemgr, u32 rsc_type, void **device)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
u32 stream;
|
||
|
void *result;
|
||
|
struct fimc_is_resource *resource;
|
||
|
struct fimc_is_core *core;
|
||
|
struct fimc_is_device_ischain *ischain;
|
||
|
|
||
|
FIMC_BUG(!resourcemgr);
|
||
|
FIMC_BUG(!resourcemgr->private_data);
|
||
|
FIMC_BUG(rsc_type >= RESOURCE_TYPE_MAX);
|
||
|
|
||
|
result = NULL;
|
||
|
core = (struct fimc_is_core *)resourcemgr->private_data;
|
||
|
resource = GET_RESOURCE(resourcemgr, rsc_type);
|
||
|
if (!resource) {
|
||
|
err("[RSC] resource is NULL");
|
||
|
ret = -EINVAL;
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
switch (rsc_type) {
|
||
|
case RESOURCE_TYPE_PREPROC:
|
||
|
result = &core->preproc;
|
||
|
resource->pdev = core->preproc.pdev;
|
||
|
break;
|
||
|
case RESOURCE_TYPE_SENSOR0:
|
||
|
result = &core->sensor[RESOURCE_TYPE_SENSOR0];
|
||
|
resource->pdev = core->sensor[RESOURCE_TYPE_SENSOR0].pdev;
|
||
|
break;
|
||
|
case RESOURCE_TYPE_SENSOR1:
|
||
|
result = &core->sensor[RESOURCE_TYPE_SENSOR1];
|
||
|
resource->pdev = core->sensor[RESOURCE_TYPE_SENSOR1].pdev;
|
||
|
break;
|
||
|
case RESOURCE_TYPE_SENSOR2:
|
||
|
result = &core->sensor[RESOURCE_TYPE_SENSOR2];
|
||
|
resource->pdev = core->sensor[RESOURCE_TYPE_SENSOR2].pdev;
|
||
|
break;
|
||
|
case RESOURCE_TYPE_SENSOR3:
|
||
|
result = &core->sensor[RESOURCE_TYPE_SENSOR3];
|
||
|
resource->pdev = core->sensor[RESOURCE_TYPE_SENSOR3].pdev;
|
||
|
break;
|
||
|
#if (FIMC_IS_SENSOR_COUNT > 4)
|
||
|
case RESOURCE_TYPE_SENSOR4:
|
||
|
result = &core->sensor[RESOURCE_TYPE_SENSOR4];
|
||
|
resource->pdev = core->sensor[RESOURCE_TYPE_SENSOR4].pdev;
|
||
|
break;
|
||
|
#if (FIMC_IS_SENSOR_COUNT > 5)
|
||
|
case RESOURCE_TYPE_SENSOR5:
|
||
|
result = &core->sensor[RESOURCE_TYPE_SENSOR5];
|
||
|
resource->pdev = core->sensor[RESOURCE_TYPE_SENSOR5].pdev;
|
||
|
break;
|
||
|
#endif
|
||
|
#endif
|
||
|
case RESOURCE_TYPE_ISCHAIN:
|
||
|
for (stream = 0; stream < FIMC_IS_STREAM_COUNT; ++stream) {
|
||
|
ischain = &core->ischain[stream];
|
||
|
if (!test_bit(FIMC_IS_ISCHAIN_OPEN, &ischain->state)) {
|
||
|
result = ischain;
|
||
|
resource->pdev = ischain->pdev;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (device)
|
||
|
*device = result;
|
||
|
|
||
|
p_err:
|
||
|
dbgd_resource("%s\n", __func__);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int fimc_is_resource_get(struct fimc_is_resourcemgr *resourcemgr, u32 rsc_type)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
u32 rsccount;
|
||
|
struct fimc_is_resource *resource;
|
||
|
struct fimc_is_core *core;
|
||
|
int i;
|
||
|
|
||
|
FIMC_BUG(!resourcemgr);
|
||
|
FIMC_BUG(!resourcemgr->private_data);
|
||
|
FIMC_BUG(rsc_type >= RESOURCE_TYPE_MAX);
|
||
|
|
||
|
core = (struct fimc_is_core *)resourcemgr->private_data;
|
||
|
|
||
|
mutex_lock(&resourcemgr->rsc_lock);
|
||
|
|
||
|
rsccount = atomic_read(&core->rsccount);
|
||
|
resource = GET_RESOURCE(resourcemgr, rsc_type);
|
||
|
if (!resource) {
|
||
|
err("[RSC] resource is NULL");
|
||
|
ret = -EINVAL;
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
if (!core->pdev) {
|
||
|
err("[RSC] pdev is NULL");
|
||
|
ret = -EMFILE;
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
if (rsccount >= (FIMC_IS_STREAM_COUNT + FIMC_IS_VIDEO_SS5_NUM)) {
|
||
|
err("[RSC] Invalid rsccount(%d)", rsccount);
|
||
|
ret = -EMFILE;
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
#ifdef ENABLE_KERNEL_LOG_DUMP
|
||
|
/* to secure kernel log when there was an instance that remain open */
|
||
|
{
|
||
|
struct fimc_is_resource *resource_ischain;
|
||
|
resource_ischain = GET_RESOURCE(resourcemgr, RESOURCE_TYPE_ISCHAIN);
|
||
|
if ((rsc_type != RESOURCE_TYPE_ISCHAIN) && rsccount == 1) {
|
||
|
if (atomic_read(&resource_ischain->rsccount) == 1)
|
||
|
fimc_is_kernel_log_dump(false);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (rsccount == 0) {
|
||
|
TIME_LAUNCH_STR(LAUNCH_TOTAL);
|
||
|
pm_stay_awake(&core->pdev->dev);
|
||
|
|
||
|
resourcemgr->cluster0 = 0;
|
||
|
resourcemgr->cluster1 = 0;
|
||
|
|
||
|
#ifdef CONFIG_CMU_EWF
|
||
|
set_cmuewf(idx_ewf, 1);
|
||
|
#endif
|
||
|
#ifdef ENABLE_DVFS
|
||
|
/* dvfs controller init */
|
||
|
ret = fimc_is_dvfs_init(resourcemgr);
|
||
|
if (ret) {
|
||
|
err("%s: fimc_is_dvfs_init failed!\n", __func__);
|
||
|
goto p_err;
|
||
|
}
|
||
|
#endif
|
||
|
/* CSIS common DMA rcount set */
|
||
|
atomic_set(&core->csi_dma.rcount, 0);
|
||
|
#if defined(SECURE_CAMERA_FACE)
|
||
|
mutex_init(&core->secure_state_lock);
|
||
|
core->secure_state = FIMC_IS_STATE_UNSECURE;
|
||
|
core->scenario = 0;
|
||
|
|
||
|
info("%s: fimc-is secure state has reset\n", __func__);
|
||
|
#endif
|
||
|
core->dual_info.mode = FIMC_IS_DUAL_MODE_NOTHING;
|
||
|
core->dual_info.pre_mode = FIMC_IS_DUAL_MODE_NOTHING;
|
||
|
core->dual_info.tick_count = 0;
|
||
|
|
||
|
for (i = 0; i < MAX_SENSOR_SHARED_RSC; i++) {
|
||
|
spin_lock_init(&core->shared_rsc_slock[i]);
|
||
|
atomic_set(&core->shared_rsc_count[i], 0);
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < SENSOR_CONTROL_I2C_MAX; i++)
|
||
|
atomic_set(&core->i2c_rsccount[i], 0);
|
||
|
|
||
|
resourcemgr->global_param.state = 0;
|
||
|
resourcemgr->shot_timeout = FIMC_IS_SHOT_TIMEOUT;
|
||
|
resourcemgr->shot_timeout_tick = 0;
|
||
|
|
||
|
#ifdef ENABLE_DYNAMIC_MEM
|
||
|
ret = fimc_is_resourcemgr_init_dynamic_mem(resourcemgr);
|
||
|
if (ret) {
|
||
|
err("fimc_is_resourcemgr_initmem is fail(%d)\n", ret);
|
||
|
goto p_err;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
if (atomic_read(&resource->rsccount) == 0) {
|
||
|
switch (rsc_type) {
|
||
|
case RESOURCE_TYPE_PREPROC:
|
||
|
#if defined(CONFIG_PM)
|
||
|
pm_runtime_get_sync(&resource->pdev->dev);
|
||
|
#else
|
||
|
fimc_is_preproc_runtime_resume(&resource->pdev->dev);
|
||
|
#endif
|
||
|
set_bit(FIMC_IS_RM_COM_POWER_ON, &resourcemgr->state);
|
||
|
break;
|
||
|
case RESOURCE_TYPE_SENSOR0:
|
||
|
#ifdef CONFIG_PM
|
||
|
pm_runtime_get_sync(&resource->pdev->dev);
|
||
|
#else
|
||
|
fimc_is_sensor_runtime_resume(&resource->pdev->dev);
|
||
|
#endif
|
||
|
set_bit(FIMC_IS_RM_SS0_POWER_ON, &resourcemgr->state);
|
||
|
break;
|
||
|
case RESOURCE_TYPE_SENSOR1:
|
||
|
#ifdef CONFIG_PM
|
||
|
pm_runtime_get_sync(&resource->pdev->dev);
|
||
|
#else
|
||
|
fimc_is_sensor_runtime_resume(&resource->pdev->dev);
|
||
|
#endif
|
||
|
set_bit(FIMC_IS_RM_SS1_POWER_ON, &resourcemgr->state);
|
||
|
break;
|
||
|
case RESOURCE_TYPE_SENSOR2:
|
||
|
#ifdef CONFIG_PM
|
||
|
pm_runtime_get_sync(&resource->pdev->dev);
|
||
|
#else
|
||
|
fimc_is_sensor_runtime_resume(&resource->pdev->dev);
|
||
|
#endif
|
||
|
set_bit(FIMC_IS_RM_SS2_POWER_ON, &resourcemgr->state);
|
||
|
break;
|
||
|
case RESOURCE_TYPE_SENSOR3:
|
||
|
#ifdef CONFIG_PM
|
||
|
pm_runtime_get_sync(&resource->pdev->dev);
|
||
|
#else
|
||
|
fimc_is_sensor_runtime_resume(&resource->pdev->dev);
|
||
|
#endif
|
||
|
set_bit(FIMC_IS_RM_SS3_POWER_ON, &resourcemgr->state);
|
||
|
break;
|
||
|
case RESOURCE_TYPE_SENSOR4:
|
||
|
#ifdef CONFIG_PM
|
||
|
pm_runtime_get_sync(&resource->pdev->dev);
|
||
|
#else
|
||
|
fimc_is_sensor_runtime_resume(&resource->pdev->dev);
|
||
|
#endif
|
||
|
set_bit(FIMC_IS_RM_SS4_POWER_ON, &resourcemgr->state);
|
||
|
break;
|
||
|
case RESOURCE_TYPE_SENSOR5:
|
||
|
#ifdef CONFIG_PM
|
||
|
pm_runtime_get_sync(&resource->pdev->dev);
|
||
|
#else
|
||
|
fimc_is_sensor_runtime_resume(&resource->pdev->dev);
|
||
|
#endif
|
||
|
set_bit(FIMC_IS_RM_SS5_POWER_ON, &resourcemgr->state);
|
||
|
break;
|
||
|
case RESOURCE_TYPE_ISCHAIN:
|
||
|
if (test_bit(FIMC_IS_RM_POWER_ON, &resourcemgr->state)) {
|
||
|
err("all resource is not power off(%lX)", resourcemgr->state);
|
||
|
ret = -EINVAL;
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
ret = fimc_is_debug_open(&resourcemgr->minfo);
|
||
|
if (ret) {
|
||
|
err("fimc_is_debug_open is fail(%d)", ret);
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
ret = fimc_is_interface_open(&core->interface);
|
||
|
if (ret) {
|
||
|
err("fimc_is_interface_open is fail(%d)", ret);
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
#if defined(SECURE_CAMERA_FACE)
|
||
|
ret = fimc_is_resourcemgr_init_secure_mem(resourcemgr);
|
||
|
if (ret) {
|
||
|
err("fimc_is_resourcemgr_init_secure_mem is fail(%d)\n", ret);
|
||
|
goto p_err;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
ret = fimc_is_ischain_power(&core->ischain[0], 1);
|
||
|
if (ret) {
|
||
|
err("fimc_is_ischain_power is fail(%d)", ret);
|
||
|
fimc_is_ischain_power(&core->ischain[0], 0);
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
/* W/A for a lower version MCUCTL */
|
||
|
fimc_is_interface_reset(&core->interface);
|
||
|
|
||
|
#if !defined(ENABLE_IS_CORE) && defined(USE_MCUCTL)
|
||
|
fimc_is_hw_s_ctrl(&core->interface, 0, HW_S_CTRL_CHAIN_IRQ, 0);
|
||
|
#endif
|
||
|
|
||
|
#ifdef ENABLE_CLOCK_GATE
|
||
|
if (sysfs_debug.en_clk_gate &&
|
||
|
sysfs_debug.clk_gate_mode == CLOCK_GATE_MODE_HOST)
|
||
|
fimc_is_clk_gate_init(core);
|
||
|
#endif
|
||
|
|
||
|
set_bit(FIMC_IS_RM_ISC_POWER_ON, &resourcemgr->state);
|
||
|
set_bit(FIMC_IS_RM_POWER_ON, &resourcemgr->state);
|
||
|
|
||
|
#if defined(CONFIG_SOC_EXYNOS8895) || defined(DISABLE_CORE_IDLE_STATE)
|
||
|
/* CPU idle on/off */
|
||
|
info("%s: call cpuidle_pause()\n", __func__);
|
||
|
cpuidle_pause();
|
||
|
#endif
|
||
|
|
||
|
#ifdef CONFIG_EXYNOS_BTS
|
||
|
info("%s: call bts_update_scen(1)\n", __func__);
|
||
|
bts_update_scen(BS_CAMERA_DEFAULT, 1);
|
||
|
#endif
|
||
|
fimc_is_hw_ischain_qe_cfg();
|
||
|
|
||
|
break;
|
||
|
default:
|
||
|
err("[RSC] resource type(%d) is invalid", rsc_type);
|
||
|
BUG();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#if !defined(ENABLE_IS_CORE) && !defined(DISABLE_LIB)
|
||
|
if ((rsc_type == RESOURCE_TYPE_ISCHAIN)
|
||
|
&& (!test_and_set_bit(FIMC_IS_BINARY_LOADED, &resourcemgr->binary_state))) {
|
||
|
TIME_LAUNCH_STR(LAUNCH_DDK_LOAD);
|
||
|
ret = fimc_is_load_bin();
|
||
|
if (ret < 0) {
|
||
|
err("fimc_is_load_bin() is fail(%d)", ret);
|
||
|
clear_bit(FIMC_IS_BINARY_LOADED, &resourcemgr->binary_state);
|
||
|
goto p_err;
|
||
|
}
|
||
|
TIME_LAUNCH_END(LAUNCH_DDK_LOAD);
|
||
|
|
||
|
#ifdef CONFIG_EXYNOS_BCM_DBG_GNR
|
||
|
exynos_bcm_dbg_start();
|
||
|
dbgd_resource("exynos bcm debug was started\n");
|
||
|
#endif
|
||
|
}
|
||
|
#endif
|
||
|
fimc_is_vender_resource_get(&core->vender);
|
||
|
}
|
||
|
|
||
|
#ifdef ENABLE_HWACG_CONTROL
|
||
|
/* for CSIS HWACG */
|
||
|
if (rsccount == 0)
|
||
|
fimc_is_hw_csi_qchannel_enable_all(true);
|
||
|
#endif
|
||
|
|
||
|
atomic_inc(&resource->rsccount);
|
||
|
atomic_inc(&core->rsccount);
|
||
|
|
||
|
p_err:
|
||
|
mutex_unlock(&resourcemgr->rsc_lock);
|
||
|
|
||
|
info("[RSC] rsctype: %d, rsccount: device[%d], core[%d]\n", rsc_type,
|
||
|
atomic_read(&resource->rsccount), rsccount + 1);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int fimc_is_resource_put(struct fimc_is_resourcemgr *resourcemgr, u32 rsc_type)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
u32 rsccount;
|
||
|
struct fimc_is_resource *resource;
|
||
|
struct fimc_is_core *core;
|
||
|
|
||
|
FIMC_BUG(!resourcemgr);
|
||
|
FIMC_BUG(!resourcemgr->private_data);
|
||
|
FIMC_BUG(rsc_type >= RESOURCE_TYPE_MAX);
|
||
|
|
||
|
core = (struct fimc_is_core *)resourcemgr->private_data;
|
||
|
|
||
|
mutex_lock(&resourcemgr->rsc_lock);
|
||
|
|
||
|
rsccount = atomic_read(&core->rsccount);
|
||
|
resource = GET_RESOURCE(resourcemgr, rsc_type);
|
||
|
if (!resource) {
|
||
|
err("[RSC] resource is NULL");
|
||
|
ret = -EINVAL;
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
if (!core->pdev) {
|
||
|
err("[RSC] pdev is NULL");
|
||
|
ret = -EMFILE;
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
if (rsccount == 0) {
|
||
|
err("[RSC] Invalid rsccount(%d)\n", rsccount);
|
||
|
ret = -EMFILE;
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
/* local update */
|
||
|
if (atomic_read(&resource->rsccount) == 1) {
|
||
|
#if !defined(ENABLE_IS_CORE) && !defined(DISABLE_LIB)
|
||
|
if ((rsc_type == RESOURCE_TYPE_ISCHAIN)
|
||
|
&& (test_and_clear_bit(FIMC_IS_BINARY_LOADED, &resourcemgr->binary_state))) {
|
||
|
fimc_is_load_clear();
|
||
|
|
||
|
info("fimc_is_load_clear() done\n");
|
||
|
}
|
||
|
#endif
|
||
|
switch (rsc_type) {
|
||
|
case RESOURCE_TYPE_PREPROC:
|
||
|
#if defined(CONFIG_PM)
|
||
|
pm_runtime_put_sync(&resource->pdev->dev);
|
||
|
#else
|
||
|
fimc_is_preproc_runtime_suspend(&resource->pdev->dev);
|
||
|
#endif
|
||
|
clear_bit(FIMC_IS_RM_COM_POWER_ON, &resourcemgr->state);
|
||
|
break;
|
||
|
case RESOURCE_TYPE_SENSOR0:
|
||
|
#if defined(CONFIG_PM)
|
||
|
pm_runtime_put_sync(&resource->pdev->dev);
|
||
|
#else
|
||
|
fimc_is_sensor_runtime_suspend(&resource->pdev->dev);
|
||
|
#endif
|
||
|
clear_bit(FIMC_IS_RM_SS0_POWER_ON, &resourcemgr->state);
|
||
|
break;
|
||
|
case RESOURCE_TYPE_SENSOR1:
|
||
|
#if defined(CONFIG_PM)
|
||
|
pm_runtime_put_sync(&resource->pdev->dev);
|
||
|
#else
|
||
|
fimc_is_sensor_runtime_suspend(&resource->pdev->dev);
|
||
|
#endif
|
||
|
clear_bit(FIMC_IS_RM_SS1_POWER_ON, &resourcemgr->state);
|
||
|
break;
|
||
|
case RESOURCE_TYPE_SENSOR2:
|
||
|
#ifdef CONFIG_PM
|
||
|
pm_runtime_put_sync(&resource->pdev->dev);
|
||
|
#else
|
||
|
fimc_is_sensor_runtime_suspend(&resource->pdev->dev);
|
||
|
#endif
|
||
|
clear_bit(FIMC_IS_RM_SS2_POWER_ON, &resourcemgr->state);
|
||
|
break;
|
||
|
case RESOURCE_TYPE_SENSOR3:
|
||
|
#ifdef CONFIG_PM
|
||
|
pm_runtime_put_sync(&resource->pdev->dev);
|
||
|
#else
|
||
|
fimc_is_sensor_runtime_suspend(&resource->pdev->dev);
|
||
|
#endif
|
||
|
clear_bit(FIMC_IS_RM_SS3_POWER_ON, &resourcemgr->state);
|
||
|
break;
|
||
|
case RESOURCE_TYPE_SENSOR4:
|
||
|
#ifdef CONFIG_PM
|
||
|
pm_runtime_put_sync(&resource->pdev->dev);
|
||
|
#else
|
||
|
fimc_is_sensor_runtime_suspend(&resource->pdev->dev);
|
||
|
#endif
|
||
|
clear_bit(FIMC_IS_RM_SS4_POWER_ON, &resourcemgr->state);
|
||
|
break;
|
||
|
case RESOURCE_TYPE_SENSOR5:
|
||
|
#ifdef CONFIG_PM
|
||
|
pm_runtime_put_sync(&resource->pdev->dev);
|
||
|
#else
|
||
|
fimc_is_sensor_runtime_suspend(&resource->pdev->dev);
|
||
|
#endif
|
||
|
clear_bit(FIMC_IS_RM_SS5_POWER_ON, &resourcemgr->state);
|
||
|
break;
|
||
|
case RESOURCE_TYPE_ISCHAIN:
|
||
|
#if defined(SECURE_CAMERA_FACE)
|
||
|
ret = fimc_is_secure_func(core, NULL, FIMC_IS_SECURE_CAMERA_FACE,
|
||
|
core->scenario, SMC_SECCAM_UNPREPARE);
|
||
|
#endif
|
||
|
ret = fimc_is_itf_power_down(&core->interface);
|
||
|
if (ret)
|
||
|
err("power down cmd is fail(%d)", ret);
|
||
|
|
||
|
ret = fimc_is_ischain_power(&core->ischain[0], 0);
|
||
|
if (ret)
|
||
|
err("fimc_is_ischain_power is fail(%d)", ret);
|
||
|
|
||
|
ret = fimc_is_interface_close(&core->interface);
|
||
|
if (ret)
|
||
|
err("fimc_is_interface_close is fail(%d)", ret);
|
||
|
|
||
|
#if defined(SECURE_CAMERA_FACE)
|
||
|
ret = fimc_is_resourcemgr_deinit_secure_mem(resourcemgr);
|
||
|
if (ret)
|
||
|
err("fimc_is_resourcemgr_deinit_secure_mem is fail(%d)", ret);
|
||
|
#endif
|
||
|
|
||
|
ret = fimc_is_debug_close();
|
||
|
if (ret)
|
||
|
err("fimc_is_debug_close is fail(%d)", ret);
|
||
|
|
||
|
clear_bit(FIMC_IS_RM_ISC_POWER_ON, &resourcemgr->state);
|
||
|
|
||
|
#if defined(CONFIG_SOC_EXYNOS8895) || defined(DISABLE_CORE_IDLE_STATE)
|
||
|
/* CPU idle on/off */
|
||
|
info("%s: call cpuidle_resume()\n", __func__);
|
||
|
cpuidle_resume();
|
||
|
#endif
|
||
|
|
||
|
#ifdef CONFIG_EXYNOS_BTS
|
||
|
info("%s: call bts_update_scen(0)\n", __func__);
|
||
|
bts_update_scen(BS_CAMERA_DEFAULT, 0);
|
||
|
bts_update_scen(BS_FHD_480_ENCODING, 0);
|
||
|
#endif
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
fimc_is_vender_resource_put(&core->vender);
|
||
|
}
|
||
|
|
||
|
/* global update */
|
||
|
if (atomic_read(&core->rsccount) == 1) {
|
||
|
u32 current_min, current_max;
|
||
|
|
||
|
#ifdef CONFIG_EXYNOS_BCM_DBG_GNR
|
||
|
exynos_bcm_dbg_stop(CAMERA_DRIVER);
|
||
|
dbgd_resource("exynos bcm debug was stopped\n");
|
||
|
#endif
|
||
|
#ifdef ENABLE_DYNAMIC_MEM
|
||
|
ret = fimc_is_resourcemgr_deinit_dynamic_mem(resourcemgr);
|
||
|
if (ret)
|
||
|
err("fimc_is_resourcemgr_deinit_dynamic_mem is fail(%d)", ret);
|
||
|
#endif
|
||
|
|
||
|
current_min = (resourcemgr->cluster0 & CLUSTER_MIN_MASK) >> CLUSTER_MIN_SHIFT;
|
||
|
current_max = (resourcemgr->cluster0 & CLUSTER_MAX_MASK) >> CLUSTER_MAX_SHIFT;
|
||
|
if (current_min) {
|
||
|
C0MIN_QOS_DEL();
|
||
|
warn("[RSC] cluster0 minfreq is not removed(%dMhz)\n", current_min);
|
||
|
}
|
||
|
|
||
|
if (current_max) {
|
||
|
C0MAX_QOS_DEL();
|
||
|
warn("[RSC] cluster0 maxfreq is not removed(%dMhz)\n", current_max);
|
||
|
}
|
||
|
|
||
|
current_min = (resourcemgr->cluster1 & CLUSTER_MIN_MASK) >> CLUSTER_MIN_SHIFT;
|
||
|
current_max = (resourcemgr->cluster1 & CLUSTER_MAX_MASK) >> CLUSTER_MAX_SHIFT;
|
||
|
if (current_min) {
|
||
|
C1MIN_QOS_DEL();
|
||
|
warn("[RSC] cluster1 minfreq is not removed(%dMhz)\n", current_min);
|
||
|
}
|
||
|
|
||
|
if (current_max) {
|
||
|
C1MAX_QOS_DEL();
|
||
|
warn("[RSC] cluster1 maxfreq is not removed(%dMhz)\n", current_max);
|
||
|
}
|
||
|
|
||
|
resourcemgr->cluster0 = 0;
|
||
|
resourcemgr->cluster1 = 0;
|
||
|
#ifdef CONFIG_CMU_EWF
|
||
|
set_cmuewf(idx_ewf, 0);
|
||
|
#endif
|
||
|
|
||
|
/* clear hal version, default 1.0 */
|
||
|
resourcemgr->hal_version = IS_HAL_VER_1_0;
|
||
|
|
||
|
ret = fimc_is_runtime_suspend_post(&resource->pdev->dev);
|
||
|
if (ret)
|
||
|
err("fimc_is_runtime_suspend_post is fail(%d)", ret);
|
||
|
|
||
|
pm_relax(&core->pdev->dev);
|
||
|
|
||
|
clear_bit(FIMC_IS_RM_POWER_ON, &resourcemgr->state);
|
||
|
}
|
||
|
|
||
|
atomic_dec(&resource->rsccount);
|
||
|
atomic_dec(&core->rsccount);
|
||
|
|
||
|
p_err:
|
||
|
mutex_unlock(&resourcemgr->rsc_lock);
|
||
|
|
||
|
info("[RSC] rsctype: %d, rsccount: device[%d], core[%d]\n", rsc_type,
|
||
|
atomic_read(&resource->rsccount), rsccount - 1);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int fimc_is_resource_ioctl(struct fimc_is_resourcemgr *resourcemgr, struct v4l2_control *ctrl)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
|
||
|
FIMC_BUG(!resourcemgr);
|
||
|
FIMC_BUG(!ctrl);
|
||
|
|
||
|
switch (ctrl->id) {
|
||
|
/* APOLLO CPU0~3 */
|
||
|
case V4L2_CID_IS_DVFS_CLUSTER0:
|
||
|
{
|
||
|
u32 current_min, current_max;
|
||
|
u32 request_min, request_max;
|
||
|
|
||
|
current_min = (resourcemgr->cluster0 & CLUSTER_MIN_MASK) >> CLUSTER_MIN_SHIFT;
|
||
|
current_max = (resourcemgr->cluster0 & CLUSTER_MAX_MASK) >> CLUSTER_MAX_SHIFT;
|
||
|
request_min = (ctrl->value & CLUSTER_MIN_MASK) >> CLUSTER_MIN_SHIFT;
|
||
|
request_max = (ctrl->value & CLUSTER_MAX_MASK) >> CLUSTER_MAX_SHIFT;
|
||
|
|
||
|
if (current_min) {
|
||
|
if (request_min)
|
||
|
C0MIN_QOS_UPDATE(request_min);
|
||
|
else
|
||
|
C0MIN_QOS_DEL();
|
||
|
} else {
|
||
|
if (request_min)
|
||
|
C0MIN_QOS_ADD(request_min);
|
||
|
}
|
||
|
|
||
|
if (current_max) {
|
||
|
if (request_max)
|
||
|
C0MAX_QOS_UPDATE(request_max);
|
||
|
else
|
||
|
C0MAX_QOS_DEL();
|
||
|
} else {
|
||
|
if (request_max)
|
||
|
C0MAX_QOS_ADD(request_max);
|
||
|
}
|
||
|
|
||
|
info("[RSC] cluster0 minfreq : %dMhz\n", request_min);
|
||
|
info("[RSC] cluster0 maxfreq : %dMhz\n", request_max);
|
||
|
resourcemgr->cluster0 = (request_max << CLUSTER_MAX_SHIFT) | request_min;
|
||
|
}
|
||
|
break;
|
||
|
/* ATLAS CPU4~7 */
|
||
|
case V4L2_CID_IS_DVFS_CLUSTER1:
|
||
|
{
|
||
|
u32 current_min, current_max;
|
||
|
u32 request_min, request_max;
|
||
|
|
||
|
current_min = (resourcemgr->cluster1 & CLUSTER_MIN_MASK) >> CLUSTER_MIN_SHIFT;
|
||
|
current_max = (resourcemgr->cluster1 & CLUSTER_MAX_MASK) >> CLUSTER_MAX_SHIFT;
|
||
|
request_min = (ctrl->value & CLUSTER_MIN_MASK) >> CLUSTER_MIN_SHIFT;
|
||
|
request_max = (ctrl->value & CLUSTER_MAX_MASK) >> CLUSTER_MAX_SHIFT;
|
||
|
|
||
|
if (current_min) {
|
||
|
if (request_min)
|
||
|
C1MIN_QOS_UPDATE(request_min);
|
||
|
else
|
||
|
C1MIN_QOS_DEL();
|
||
|
} else {
|
||
|
if (request_min)
|
||
|
C1MIN_QOS_ADD(request_min);
|
||
|
}
|
||
|
|
||
|
if (current_max) {
|
||
|
if (request_max)
|
||
|
C1MAX_QOS_UPDATE(request_max);
|
||
|
else
|
||
|
C1MAX_QOS_DEL();
|
||
|
} else {
|
||
|
if (request_max)
|
||
|
C1MAX_QOS_ADD(request_max);
|
||
|
}
|
||
|
|
||
|
info("[RSC] cluster1 minfreq : %dMhz\n", request_min);
|
||
|
info("[RSC] cluster1 maxfreq : %dMhz\n", request_max);
|
||
|
resourcemgr->cluster1 = (request_max << CLUSTER_MAX_SHIFT) | request_min;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
void fimc_is_resource_set_global_param(struct fimc_is_resourcemgr *resourcemgr, void *device)
|
||
|
{
|
||
|
bool video_mode;
|
||
|
struct fimc_is_device_ischain *ischain = device;
|
||
|
struct fimc_is_global_param *global_param = &resourcemgr->global_param;
|
||
|
|
||
|
mutex_lock(&global_param->lock);
|
||
|
|
||
|
if (!global_param->state) {
|
||
|
video_mode = IS_VIDEO_SCENARIO(ischain->setfile & FIMC_IS_SETFILE_MASK);
|
||
|
global_param->video_mode = video_mode;
|
||
|
ischain->hardware->video_mode = video_mode;
|
||
|
minfo("video mode %d\n", ischain, video_mode);
|
||
|
}
|
||
|
|
||
|
set_bit(ischain->instance, &global_param->state);
|
||
|
|
||
|
mutex_unlock(&global_param->lock);
|
||
|
}
|
||
|
|
||
|
void fimc_is_resource_clear_global_param(struct fimc_is_resourcemgr *resourcemgr, void *device)
|
||
|
{
|
||
|
struct fimc_is_device_ischain *ischain = device;
|
||
|
struct fimc_is_global_param *global_param = &resourcemgr->global_param;
|
||
|
|
||
|
mutex_lock(&global_param->lock);
|
||
|
|
||
|
clear_bit(ischain->instance, &global_param->state);
|
||
|
|
||
|
if (!global_param->state) {
|
||
|
global_param->video_mode = false;
|
||
|
ischain->hardware->video_mode = false;
|
||
|
}
|
||
|
|
||
|
mutex_unlock(&global_param->lock);
|
||
|
}
|
||
|
|
||
|
int fimc_is_logsync(struct fimc_is_interface *itf, u32 sync_id, u32 msg_test_id)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
|
||
|
/* print kernel sync log */
|
||
|
log_sync(sync_id);
|
||
|
|
||
|
#ifdef ENABLE_FW_SYNC_LOG
|
||
|
ret = fimc_is_hw_msg_test(itf, sync_id, msg_test_id);
|
||
|
if (ret)
|
||
|
err("fimc_is_hw_msg_test(%d)", ret);
|
||
|
#endif
|
||
|
return ret;
|
||
|
}
|