msm: camera: cpas: HW workaround for SDM670_1_1
HW workaround to select PriorityLvl for IFE0 and IFE1
because HurryLvl is not working as expected.
Change-Id: I3a16d6700b1afe008fb5a9763c5f3a41d2557134
Signed-off-by: Alok Pandey <akumarpa@codeaurora.org>
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-cpas.txt b/Documentation/devicetree/bindings/media/video/msm-cam-cpas.txt
index 4b16103..f9bda3b 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cam-cpas.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-cpas.txt
@@ -147,6 +147,13 @@
Definition: Bool property specifying whether Clients are connected
through CAMNOC for AXI access.
+- nvmem-cells
+ Usage: optional
+ Definition: nvmem cell node
+
+- nvmem-cell-names
+ Usage: required
+ Definition: If nvmem node is present, cell name is required
===================================================================
Third Level Node - CAM AXI Port properties
===================================================================
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c
index b18af0a..2837f5b 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c
@@ -140,6 +140,7 @@ int cam_cpas_soc_init_resources(struct cam_hw_soc_info *soc_info,
irq_handler_t irq_handler, void *irq_data)
{
int rc = 0;
+ struct cam_cpas_private_soc *soc_private;
rc = cam_soc_util_get_dt_properties(soc_info);
if (rc) {
@@ -173,6 +174,12 @@ int cam_cpas_soc_init_resources(struct cam_hw_soc_info *soc_info,
goto free_soc_private;
}
+ soc_private = soc_info->soc_private;
+ soc_private->soc_id = cam_soc_util_get_soc_id();
+ soc_private->hw_rev = cam_soc_util_get_hw_revision_node(soc_info);
+ CAM_DBG(CAM_CPAS, "soc id %d hw_rev %d",
+ soc_private->soc_id, soc_private->hw_rev);
+
return rc;
free_soc_private:
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h
index fe0187e..a93c063 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h
@@ -17,7 +17,6 @@
#include "cam_cpas_hw.h"
#define CAM_REGULATOR_LEVEL_MAX 16
-
/**
* struct cam_cpas_vdd_ahb_mapping : Voltage to ahb level mapping
*
@@ -42,7 +41,8 @@ struct cam_cpas_vdd_ahb_mapping {
* @axi_port_list_node : Node representing AXI Ports list
* @num_vdd_ahb_mapping : Number of vdd to ahb level mapping supported
* @vdd_ahb : AHB level mapping info for the supported vdd levels
- *
+ * @soc_id : SOC id
+ * @hw_rev : Camera hw revision
*/
struct cam_cpas_private_soc {
const char *arch_compat;
@@ -54,6 +54,8 @@ struct cam_cpas_private_soc {
struct device_node *axi_port_list_node;
uint32_t num_vdd_ahb_mapping;
struct cam_cpas_vdd_ahb_mapping vdd_ahb[CAM_REGULATOR_LEVEL_MAX];
+ uint32_t soc_id;
+ uint32_t hw_rev;
};
int cam_cpas_soc_init_resources(struct cam_hw_soc_info *soc_info,
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c
index 0533ed8..8d08079 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c
@@ -114,6 +114,15 @@ static int cam_cpastop_setup_regbase_indices(struct cam_hw_soc_info *soc_info,
return -EINVAL;
}
+ rc = cam_common_util_get_string_index(soc_info->mem_block_name,
+ soc_info->num_mem_block, "core_top_csr_tcsr", &index);
+ if ((rc == 0) && (index < num_reg_map)) {
+ regbase_index[CAM_CPAS_REG_CSR_TCSR] = index;
+ } else {
+ CAM_DBG(CAM_CPAS, "regbase not found for CAMNOC, rc=%d, %d %d",
+ rc, index, num_reg_map);
+ }
+
return 0;
}
@@ -456,6 +465,9 @@ static irqreturn_t cam_cpastop_handle_irq(int irq_num, void *data)
static int cam_cpastop_poweron(struct cam_hw_info *cpas_hw)
{
int i;
+ struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
+ struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
+ struct cam_cpas_private_soc *soc_private = soc_info->soc_private;
cam_cpastop_reset_irq(cpas_hw);
@@ -478,6 +490,29 @@ static int cam_cpastop_poweron(struct cam_hw_info *cpas_hw)
}
}
+ if ((soc_private && soc_private->soc_id == SDM670_SOC_ID) &&
+ (soc_private->hw_rev == SDM670_V1_1)) {
+
+ struct cam_cpas_reg *reg_info;
+ int tcsr_index;
+ void __iomem *mem_base;
+
+ reg_info = &camnoc_info->errata_wa_list->tcsr_reg.
+ tcsr_conn_box_spare_0;
+ tcsr_index = cpas_core->regbase_index[CAM_CPAS_REG_CSR_TCSR];
+ if (tcsr_index == -1) {
+ CAM_DBG(CAM_CPAS, "index in not initialized");
+ return 0;
+ }
+ mem_base = soc_info->reg_map[tcsr_index].mem_base;
+
+ reg_info->value = TCSR_CONN_SET;
+ cam_io_w_mb(reg_info->value, mem_base + reg_info->offset);
+ CAM_DBG(CAM_CPAS, "tcsr(0x%lx) value %d",
+ (unsigned long int)mem_base + reg_info->offset,
+ cam_io_r_mb(mem_base + reg_info->offset));
+ }
+
return 0;
}
@@ -489,6 +524,8 @@ static int cam_cpastop_poweroff(struct cam_hw_info *cpas_hw)
int rc = 0;
struct cam_cpas_hw_errata_wa_list *errata_wa_list =
camnoc_info->errata_wa_list;
+ struct cam_cpas_private_soc *soc_private =
+ cpas_hw->soc_info.soc_private;
if (!errata_wa_list)
return 0;
@@ -512,6 +549,28 @@ static int cam_cpastop_poweroff(struct cam_hw_info *cpas_hw)
}
}
+ if ((soc_private && soc_private->soc_id == SDM670_SOC_ID) &&
+ (soc_private->hw_rev == SDM670_V1_1)) {
+
+ struct cam_cpas_reg *reg_info;
+ int tcsr_index;
+ void __iomem *mem_base;
+
+ reg_info = &camnoc_info->errata_wa_list->tcsr_reg.
+ tcsr_conn_box_spare_0;
+ reg_info->value = TCSR_CONN_RESET;
+ tcsr_index = cpas_core->regbase_index[CAM_CPAS_REG_CSR_TCSR];
+ if (tcsr_index == -1) {
+ CAM_DBG(CAM_CPAS, "index in not initialized");
+ return 0;
+ }
+ mem_base = soc_info->reg_map[tcsr_index].mem_base;
+ cam_io_w_mb(reg_info->value, mem_base + reg_info->offset);
+ CAM_DBG(CAM_CPAS, "tcsr(0x%lx) value %d",
+ (unsigned long int)mem_base + reg_info->offset,
+ cam_io_r_mb(mem_base + reg_info->offset));
+ }
+
return rc;
}
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.h b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.h
index 73f7e9b..080f6e6 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -162,14 +162,27 @@ struct cam_cpas_hw_errata_wa {
};
/**
+ * struct cam_camnoc_tcsr_regs : Top control Status register
+ *
+ * @tcsr_conn_box_spare_0: spare register to select PriorityLvl
+ * for IFE0 and IFE1 (HW workaround for SDM670 1.1)
+ *
+ */
+struct cam_camnoc_tcsr_regs {
+ struct cam_cpas_reg tcsr_conn_box_spare_0;
+};
+
+/**
* struct cam_cpas_hw_errata_wa_list : List of HW Errata workaround info
*
* @camnoc_flush_slave_pending_trans: Errata workaround info for flushing
* camnoc slave pending transactions before turning off CPAS_TOP gdsc
+ * @tcsr_reg: HW workaround to select PriorityLvl for IFE0 and IFE(SDM670_1.1)
*
*/
struct cam_cpas_hw_errata_wa_list {
struct cam_cpas_hw_errata_wa camnoc_flush_slave_pending_trans;
+ struct cam_camnoc_tcsr_regs tcsr_reg;
};
/**
@@ -200,6 +213,7 @@ struct cam_camnoc_err_logger_info {
uint32_t errlog3_high;
};
+
/**
* struct cam_camnoc_info : Overall CAMNOC settings info
*
@@ -210,7 +224,6 @@ struct cam_camnoc_err_logger_info {
* @irq_err_size: Array size of IRQ Error settings
* @err_logger: Pointer to CAMNOC IRQ Error logger read registers
* @errata_wa_list: HW Errata workaround info
- *
*/
struct cam_camnoc_info {
struct cam_camnoc_specific *specific;
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v170_110.h b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v170_110.h
index 3c572f0..c1048a0 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v170_110.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v170_110.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -14,6 +14,8 @@
#define _CPASTOP_V170_110_H_
#define TEST_IRQ_ENABLE 0
+#define TCSR_CONN_RESET 0x0
+#define TCSR_CONN_SET 0x3
static struct cam_camnoc_irq_sbm cam_cpas110_irq_sbm = {
.sbm_enable = {
@@ -528,6 +530,14 @@ static struct cam_cpas_hw_errata_wa_list cam170_cpas110_errata_wa_list = {
.value = 0, /* expected to be 0 */
},
},
+ .tcsr_reg = {
+ .tcsr_conn_box_spare_0 = {
+ .enable = true,
+ .access_type = CAM_REG_TYPE_READ_WRITE,
+ .masked_value = 0,
+ .offset = 0xB3E4,
+ },
+ },
};
static struct cam_camnoc_info cam170_cpas110_camnoc_info = {
diff --git a/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h b/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h
index c844ef7..d1492fe 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -32,6 +32,7 @@
enum cam_cpas_reg_base {
CAM_CPAS_REG_CPASTOP,
CAM_CPAS_REG_CAMNOC,
+ CAM_CPAS_REG_CSR_TCSR,
CAM_CPAS_REG_CAMSS,
CAM_CPAS_REG_MAX
};
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
index 0b1896f..d0a13ab 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
@@ -15,8 +15,62 @@
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
+#include <soc/qcom/socinfo.h>
#include "cam_soc_util.h"
#include "cam_debug_util.h"
+#include <linux/nvmem-consumer.h>
+
+uint32_t cam_soc_util_get_soc_id(void)
+{
+ return socinfo_get_id();
+}
+#if defined(CONFIG_NVMEM) && defined(CONFIG_QCOM_QFPROM)
+uint32_t cam_soc_util_get_hw_revision_node(struct cam_hw_soc_info *soc_info)
+{
+ struct nvmem_cell *cell;
+ ssize_t len;
+ uint32_t *buf, hw_rev;
+ struct platform_device *pdev;
+
+ pdev = soc_info->pdev;
+ /* read the soc hw revision and select revision node */
+ cell = nvmem_cell_get(&pdev->dev, "minor_rev");
+ if (IS_ERR_OR_NULL(cell)) {
+ if (PTR_ERR(cell) == -EPROBE_DEFER) {
+ CAM_ERR(CAM_UTIL, "Err to get nvmem cell: ret=%ld",
+ PTR_ERR(cell));
+ return -EINVAL;
+ }
+ CAM_ERR(CAM_UTIL, "No DTS entry");
+ return 0;
+ }
+
+ if (PTR_ERR(cell) == -ENOENT) {
+ CAM_DBG(CAM_UTIL, "nvme cell not found");
+ return 0;
+ }
+
+ buf = nvmem_cell_read(cell, &len);
+ nvmem_cell_put(cell);
+
+ if (IS_ERR_OR_NULL(buf)) {
+ CAM_ERR(CAM_UTIL, "Unable to read nvmem cell: ret=%ld",
+ PTR_ERR(buf));
+ return -EINVAL;
+ }
+
+ CAM_DBG(CAM_UTIL, "hw_rev = %u", *buf);
+ hw_rev = (*buf >> 28) & 0x3;
+ kfree(buf);
+
+ return hw_rev;
+}
+#else
+uint32_t cam_soc_util_get_hw_revision_node(struct cam_hw_soc_info *soc_info)
+{
+ return 0;
+}
+#endif
int cam_soc_util_get_level_from_string(const char *string,
enum cam_vote_level *level)
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h
index 4b57d54..1f2d46d 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -40,6 +40,11 @@
/* maximum number of device clock */
#define CAM_SOC_MAX_CLK 32
+/* soc id */
+#define SDM670_SOC_ID 336
+
+/* Minor Version */
+#define SDM670_V1_1 0x1
/**
* enum cam_vote_level - Enum for voting level
*
@@ -615,5 +620,23 @@ void cam_soc_util_clk_disable_default(struct cam_hw_soc_info *soc_info);
int cam_soc_util_clk_enable_default(struct cam_hw_soc_info *soc_info,
enum cam_vote_level clk_level);
+/**
+ * cam_soc_util_get_soc_id()
+ *
+ * @brief: Read soc id
+ *
+ * @return SOC id
+ */
+uint32_t cam_soc_util_get_soc_id(void);
+/**
+ * cam_soc_util_get_hw_revision_node()
+ *
+ * @brief: Camera HW ID
+ *
+ * @soc_info: Device soc information
+ *
+ * @return HW id
+ */
+uint32_t cam_soc_util_get_hw_revision_node(struct cam_hw_soc_info *soc_info);
#endif /* _CAM_SOC_UTIL_H_ */