msm: camera: cdm: Add support for different CDM hardware
Different CDM hardware have different capability and registers. With old register space, handling new features and operations would have been a complex task. This change takes care of old version of CDM and also changes the regspace to provide every register's access to CDM. This change further adds support for "arbitration" in case of multi-context CDMs. Exports reset functionality to clients, detection of CDM hang. Flushing the CDM requests and dumping the FIFO content for all contexts. It also adds submitting "debug_gen_irq" as BL_done IRQ is only an indication for availability of FIFO's. The AHB operations are completed can only be known if the added "debug_gen_irqs" gets executed and are received by the CDM. CRs-Fixed: 2594541 Change-Id: I9846b1c5320ba652c5d3b7d83d616d2dabc843e1 Signed-off-by: Abhilash Kumar <krabhi@codeaurora.org> Signed-off-by: Trishansh Bhardwaj <tbhardwa@codeaurora.org>
这个提交包含在:
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
@@ -15,45 +15,35 @@
|
||||
#include "cam_cdm.h"
|
||||
#include "cam_soc_util.h"
|
||||
#include "cam_io_util.h"
|
||||
#include "cam_cdm_soc.h"
|
||||
|
||||
#define CAM_CDM_OFFSET_FROM_REG(x, y) ((x)->offsets[y].offset)
|
||||
#define CAM_CDM_ATTR_FROM_REG(x, y) ((x)->offsets[y].attribute)
|
||||
|
||||
bool cam_cdm_read_hw_reg(struct cam_hw_info *cdm_hw,
|
||||
enum cam_cdm_regs reg, uint32_t *value)
|
||||
uint32_t reg, uint32_t *value)
|
||||
{
|
||||
void __iomem *reg_addr;
|
||||
struct cam_cdm *cdm = (struct cam_cdm *)cdm_hw->core_info;
|
||||
void __iomem *base =
|
||||
cdm_hw->soc_info.reg_map[CAM_HW_CDM_BASE_INDEX].mem_base;
|
||||
resource_size_t mem_len =
|
||||
cdm_hw->soc_info.reg_map[CAM_HW_CDM_BASE_INDEX].size;
|
||||
|
||||
CAM_DBG(CAM_CDM, "E: b=%pK blen=%d reg=%x off=%x", (void __iomem *)base,
|
||||
(int)mem_len, reg, (CAM_CDM_OFFSET_FROM_REG(cdm->offset_tbl,
|
||||
reg)));
|
||||
CAM_DBG(CAM_CDM, "E: b=%pK reg=%x off=%x", (void __iomem *)base,
|
||||
reg, (CAM_CDM_OFFSET_FROM_REG(cdm->offset_tbl, reg)));
|
||||
CAM_DBG(CAM_CDM, "E: b=%pK blen=%d off=%x", (void __iomem *)base,
|
||||
(int)mem_len, reg);
|
||||
|
||||
if ((reg > cdm->offset_tbl->offset_max_size) ||
|
||||
(reg > cdm->offset_tbl->last_offset)) {
|
||||
CAM_ERR_RATE_LIMIT(CAM_CDM, "Invalid reg=%d\n", reg);
|
||||
reg_addr = (base + reg);
|
||||
if (reg_addr > (base + mem_len)) {
|
||||
CAM_ERR_RATE_LIMIT(CAM_CDM,
|
||||
"Invalid mapped region %d", reg);
|
||||
goto permission_error;
|
||||
} else {
|
||||
reg_addr = (base + (CAM_CDM_OFFSET_FROM_REG(
|
||||
cdm->offset_tbl, reg)));
|
||||
if (reg_addr > (base + mem_len)) {
|
||||
CAM_ERR_RATE_LIMIT(CAM_CDM,
|
||||
"Invalid mapped region %d", reg);
|
||||
goto permission_error;
|
||||
}
|
||||
*value = cam_io_r_mb(reg_addr);
|
||||
CAM_DBG(CAM_CDM, "X b=%pK reg=%x off=%x val=%x",
|
||||
(void __iomem *)base, reg,
|
||||
(CAM_CDM_OFFSET_FROM_REG(cdm->offset_tbl, reg)),
|
||||
*value);
|
||||
return false;
|
||||
}
|
||||
*value = cam_io_r_mb(reg_addr);
|
||||
CAM_DBG(CAM_CDM, "X b=%pK off=%x val=%x",
|
||||
(void __iomem *)base, reg,
|
||||
*value);
|
||||
return false;
|
||||
|
||||
permission_error:
|
||||
*value = 0;
|
||||
return true;
|
||||
@@ -61,36 +51,27 @@ permission_error:
|
||||
}
|
||||
|
||||
bool cam_cdm_write_hw_reg(struct cam_hw_info *cdm_hw,
|
||||
enum cam_cdm_regs reg, uint32_t value)
|
||||
uint32_t reg, uint32_t value)
|
||||
{
|
||||
void __iomem *reg_addr;
|
||||
struct cam_cdm *cdm = (struct cam_cdm *)cdm_hw->core_info;
|
||||
void __iomem *base =
|
||||
cdm_hw->soc_info.reg_map[CAM_HW_CDM_BASE_INDEX].mem_base;
|
||||
resource_size_t mem_len =
|
||||
cdm_hw->soc_info.reg_map[CAM_HW_CDM_BASE_INDEX].size;
|
||||
|
||||
CAM_DBG(CAM_CDM, "E: b=%pK reg=%x off=%x val=%x", (void __iomem *)base,
|
||||
reg, (CAM_CDM_OFFSET_FROM_REG(cdm->offset_tbl, reg)), value);
|
||||
CAM_DBG(CAM_CDM, "E: b=%pK off=%x val=%x", (void __iomem *)base,
|
||||
reg, value);
|
||||
|
||||
if ((reg > cdm->offset_tbl->offset_max_size) ||
|
||||
(reg > cdm->offset_tbl->last_offset)) {
|
||||
CAM_ERR_RATE_LIMIT(CAM_CDM, "CDM accessing invalid reg=%d\n",
|
||||
reg_addr = (base + reg);
|
||||
if (reg_addr > (base + mem_len)) {
|
||||
CAM_ERR_RATE_LIMIT(CAM_CDM,
|
||||
"Accessing invalid region:%d\n",
|
||||
reg);
|
||||
goto permission_error;
|
||||
} else {
|
||||
reg_addr = (base + CAM_CDM_OFFSET_FROM_REG(
|
||||
cdm->offset_tbl, reg));
|
||||
if (reg_addr > (base + mem_len)) {
|
||||
CAM_ERR_RATE_LIMIT(CAM_CDM,
|
||||
"Accessing invalid region %d:%d\n",
|
||||
reg, (CAM_CDM_OFFSET_FROM_REG(
|
||||
cdm->offset_tbl, reg)));
|
||||
goto permission_error;
|
||||
}
|
||||
cam_io_w_mb(value, reg_addr);
|
||||
return false;
|
||||
}
|
||||
cam_io_w_mb(value, reg_addr);
|
||||
return false;
|
||||
|
||||
permission_error:
|
||||
return true;
|
||||
|
||||
@@ -99,7 +80,7 @@ permission_error:
|
||||
int cam_cdm_soc_load_dt_private(struct platform_device *pdev,
|
||||
struct cam_cdm_private_dt_data *ptr)
|
||||
{
|
||||
int i, rc = -EINVAL;
|
||||
int i, rc = -EINVAL, num_fifo_entries = 0;
|
||||
|
||||
ptr->dt_num_supported_clients = of_property_count_strings(
|
||||
pdev->dev.of_node,
|
||||
@@ -111,7 +92,7 @@ int cam_cdm_soc_load_dt_private(struct platform_device *pdev,
|
||||
CAM_ERR(CAM_CDM, "Invalid count of client names count=%d",
|
||||
ptr->dt_num_supported_clients);
|
||||
rc = -EINVAL;
|
||||
return rc;
|
||||
goto end;
|
||||
}
|
||||
if (ptr->dt_num_supported_clients < 0) {
|
||||
CAM_DBG(CAM_CDM, "No cdm client names found");
|
||||
@@ -127,10 +108,43 @@ int cam_cdm_soc_load_dt_private(struct platform_device *pdev,
|
||||
ptr->dt_cdm_client_name[i]);
|
||||
if (rc < 0) {
|
||||
CAM_ERR(CAM_CDM, "Reading cdm-client-names failed");
|
||||
break;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
ptr->config_fifo = of_property_read_bool(pdev->dev.of_node,
|
||||
"config-fifo");
|
||||
if (ptr->config_fifo) {
|
||||
num_fifo_entries = of_property_count_u32_elems(
|
||||
pdev->dev.of_node,
|
||||
"fifo-depths");
|
||||
if (num_fifo_entries != CAM_CDM_NUM_BL_FIFO) {
|
||||
CAM_ERR(CAM_CDM,
|
||||
"Wrong number of configurable FIFOs %d",
|
||||
num_fifo_entries);
|
||||
rc = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
for (i = 0; i < num_fifo_entries; i++) {
|
||||
rc = of_property_read_u32_index(pdev->dev.of_node,
|
||||
"fifo-depths", i, &ptr->fifo_depth[i]);
|
||||
if (rc < 0) {
|
||||
CAM_ERR(CAM_CDM,
|
||||
"Unable to read fifo-depth rc %d",
|
||||
rc);
|
||||
goto end;
|
||||
}
|
||||
CAM_DBG(CAM_CDM, "FIFO%d depth is %d",
|
||||
i, ptr->fifo_depth[i]);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < CAM_CDM_BL_FIFO_MAX; i++) {
|
||||
ptr->fifo_depth[i] = CAM_CDM_BL_FIFO_LENGTH_MAX_DEFAULT;
|
||||
CAM_DBG(CAM_CDM, "FIFO%d depth is %d",
|
||||
i, ptr->fifo_depth[i]);
|
||||
}
|
||||
}
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -140,6 +154,7 @@ int cam_hw_cdm_soc_get_dt_properties(struct cam_hw_info *cdm_hw,
|
||||
int rc;
|
||||
struct cam_hw_soc_info *soc_ptr;
|
||||
const struct of_device_id *id;
|
||||
struct cam_cdm *cdm_core = cdm_hw->core_info;
|
||||
|
||||
if (!cdm_hw || (cdm_hw->soc_info.soc_private)
|
||||
|| !(cdm_hw->soc_info.pdev))
|
||||
@@ -150,38 +165,44 @@ int cam_hw_cdm_soc_get_dt_properties(struct cam_hw_info *cdm_hw,
|
||||
rc = cam_soc_util_get_dt_properties(soc_ptr);
|
||||
if (rc != 0) {
|
||||
CAM_ERR(CAM_CDM, "Failed to retrieve the CDM dt properties");
|
||||
} else {
|
||||
soc_ptr->soc_private = kzalloc(
|
||||
sizeof(struct cam_cdm_private_dt_data),
|
||||
GFP_KERNEL);
|
||||
if (!soc_ptr->soc_private)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = cam_cdm_soc_load_dt_private(soc_ptr->pdev,
|
||||
soc_ptr->soc_private);
|
||||
if (rc != 0) {
|
||||
CAM_ERR(CAM_CDM, "Failed to load CDM dt private data");
|
||||
goto error;
|
||||
}
|
||||
id = of_match_node(table, soc_ptr->pdev->dev.of_node);
|
||||
if ((!id) || !(id->data)) {
|
||||
CAM_ERR(CAM_CDM, "Failed to retrieve the CDM id table");
|
||||
goto error;
|
||||
}
|
||||
CAM_DBG(CAM_CDM, "CDM Hw Id compatible =%s", id->compatible);
|
||||
((struct cam_cdm *)cdm_hw->core_info)->offset_tbl =
|
||||
(struct cam_cdm_reg_offset_table *)id->data;
|
||||
strlcpy(((struct cam_cdm *)cdm_hw->core_info)->name,
|
||||
id->compatible,
|
||||
sizeof(((struct cam_cdm *)cdm_hw->core_info)->name));
|
||||
goto end;
|
||||
}
|
||||
|
||||
return rc;
|
||||
soc_ptr->soc_private = kzalloc(
|
||||
sizeof(struct cam_cdm_private_dt_data),
|
||||
GFP_KERNEL);
|
||||
if (!soc_ptr->soc_private)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = cam_cdm_soc_load_dt_private(soc_ptr->pdev,
|
||||
soc_ptr->soc_private);
|
||||
if (rc != 0) {
|
||||
CAM_ERR(CAM_CDM, "Failed to load CDM dt private data");
|
||||
goto error;
|
||||
}
|
||||
|
||||
id = of_match_node(table, soc_ptr->pdev->dev.of_node);
|
||||
if ((!id) || !(id->data)) {
|
||||
CAM_ERR(CAM_CDM, "Failed to retrieve the CDM id table");
|
||||
goto error;
|
||||
}
|
||||
cdm_core->offsets =
|
||||
(struct cam_cdm_hw_reg_offset *)id->data;
|
||||
|
||||
CAM_DBG(CAM_CDM, "name %s", cdm_core->name);
|
||||
|
||||
snprintf(cdm_core->name, sizeof(cdm_core->name) + 1, "%s%d",
|
||||
id->compatible, soc_ptr->index);
|
||||
|
||||
CAM_DBG(CAM_CDM, "name %s", cdm_core->name);
|
||||
|
||||
goto end;
|
||||
|
||||
error:
|
||||
rc = -EINVAL;
|
||||
kfree(soc_ptr->soc_private);
|
||||
soc_ptr->soc_private = NULL;
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
在新工单中引用
屏蔽一个用户