Browse Source

msm: camera: icp: Support processor-specific HFI register offsets

The HFI interface registers will have a different base address
on the LX7 processor. We can utilize the newly added HFI ops to
abstract the calculation of the address by kicking that info out
to the device interface. The HFI register definitions have been
tweaked to support offsets based on the calculated addresses.

CRs-Fixed: 2722486
Change-Id: I93b9b2827ec0820eaac6ee2e6a611363b96a3223
Signed-off-by: Fernando Pacheco <[email protected]>
Fernando Pacheco 5 năm trước cách đây
mục cha
commit
528d44a312

+ 6 - 8
drivers/cam_icp/fw_inc/hfi_intf.h

@@ -33,7 +33,6 @@ struct hfi_mem {
  * @qdss: qdss mapped memory for fw
  * @io_mem: io memory info
  * @io_mem2: 2nd io memory info
- * @icp_base: icp base address
  */
 struct hfi_mem_info {
 	struct hfi_mem qtbl;
@@ -46,17 +45,18 @@ struct hfi_mem_info {
 	struct hfi_mem qdss;
 	struct hfi_mem io_mem;
 	struct hfi_mem io_mem2;
-	void __iomem *icp_base;
 };
 
 /**
  * struct hfi_ops
  * @irq_raise: called to raise H2ICP interrupt
  * @irq_enable: called to enable interrupts from ICP
+ * @iface_addr: called to get interface registers base address
  */
 struct hfi_ops {
 	void (*irq_raise)(void *data);
 	void (*irq_enable)(void *data);
+	void __iomem *(*iface_addr)(void *data);
 };
 
 /**
@@ -84,12 +84,11 @@ int hfi_read_message(uint32_t *pmsg, uint8_t q_id, uint32_t *words_read);
  * @hfi_ops: processor-specific hfi ops
  * @priv: device private data
  * @event_driven_mode: event mode
- * @icp_base: icp base address
  *
  * Returns success(zero)/failure(non zero)
  */
-int cam_hfi_init(struct hfi_mem_info *hfi_mem, struct hfi_ops *hfi_ops,
-		void *priv, uint8_t event_driven_mode, void *__iomem icp_base);
+int cam_hfi_init(struct hfi_mem_info *hfi_mem, const struct hfi_ops *hfi_ops,
+		void *priv, uint8_t event_driven_mode);
 
 /**
  * hfi_get_hw_caps() - hardware capabilities from firmware
@@ -110,7 +109,7 @@ void hfi_send_system_cmd(uint32_t type, uint64_t data, uint32_t size);
 /**
  * cam_hfi_deinit() - cleanup HFI
  */
-void cam_hfi_deinit(void __iomem *icp_base);
+void cam_hfi_deinit(void);
 /**
  * hfi_set_debug_level() - set debug level
  * @a5_dbg_type: 1 for debug_q & 2 for qdss
@@ -152,11 +151,10 @@ int hfi_cmd_ubwc_config(uint32_t *ubwc_cfg);
 /**
  * cam_hfi_resume() - function to resume
  * @hfi_mem: hfi memory info
- * @icp_base: icp base address
  *
  * Returns success(zero)/failure(non zero)
  */
-int cam_hfi_resume(struct hfi_mem_info *hfi_mem, void __iomem *icp_base);
+int cam_hfi_resume(struct hfi_mem_info *hfi_mem);
 
 /**
  * cam_hfi_queue_dump() - utility function to dump hfi queues

+ 17 - 22
drivers/cam_icp/fw_inc/hfi_reg.h

@@ -9,27 +9,24 @@
 #include <linux/types.h>
 #include "hfi_intf.h"
 
-/* start of ICP CSR registers */
-#define HFI_REG_A5_HW_VERSION                   0x0
+/* general purpose registers */
+#define GEN_PURPOSE_REG(n)              (n * 4)
 
-/* general purpose registers from */
-#define HFI_REG_FW_VERSION                      0x44
-#define HFI_REG_HOST_ICP_INIT_REQUEST           0x48
-#define HFI_REG_ICP_HOST_INIT_RESPONSE          0x4C
-#define HFI_REG_SHARED_MEM_PTR                  0x50
-#define HFI_REG_SHARED_MEM_SIZE                 0x54
-#define HFI_REG_QTBL_PTR                        0x58
-#define HFI_REG_UNCACHED_HEAP_PTR               0x5C
-#define HFI_REG_UNCACHED_HEAP_SIZE              0x60
-#define HFI_REG_QDSS_IOVA                       0x6C
-#define HFI_REG_SFR_PTR                         0x68
-#define HFI_REG_QDSS_IOVA_SIZE                  0x70
-#define HFI_REG_IO_REGION_IOVA                  0x74
-#define HFI_REG_IO_REGION_SIZE                  0x78
-#define HFI_REG_IO2_REGION_IOVA                 0x7C
-#define HFI_REG_IO2_REGION_SIZE                 0x80
-
-/* end of ICP CSR registers */
+#define HFI_REG_FW_VERSION              GEN_PURPOSE_REG(1)
+#define HFI_REG_HOST_ICP_INIT_REQUEST   GEN_PURPOSE_REG(2)
+#define HFI_REG_ICP_HOST_INIT_RESPONSE  GEN_PURPOSE_REG(3)
+#define HFI_REG_SHARED_MEM_PTR          GEN_PURPOSE_REG(4)
+#define HFI_REG_SHARED_MEM_SIZE         GEN_PURPOSE_REG(5)
+#define HFI_REG_QTBL_PTR                GEN_PURPOSE_REG(6)
+#define HFI_REG_UNCACHED_HEAP_PTR       GEN_PURPOSE_REG(7)
+#define HFI_REG_UNCACHED_HEAP_SIZE      GEN_PURPOSE_REG(8)
+#define HFI_REG_SFR_PTR                 GEN_PURPOSE_REG(10)
+#define HFI_REG_QDSS_IOVA               GEN_PURPOSE_REG(11)
+#define HFI_REG_QDSS_IOVA_SIZE          GEN_PURPOSE_REG(12)
+#define HFI_REG_IO_REGION_IOVA          GEN_PURPOSE_REG(13)
+#define HFI_REG_IO_REGION_SIZE          GEN_PURPOSE_REG(14)
+#define HFI_REG_IO2_REGION_IOVA         GEN_PURPOSE_REG(15)
+#define HFI_REG_IO2_REGION_SIZE         GEN_PURPOSE_REG(16)
 
 /* start of Queue table and queues */
 #define MAX_ICP_HFI_QUEUES                      4
@@ -278,7 +275,6 @@ struct hfi_qtbl {
  * @cmd_q_state: State of command queue
  * @mutex msg_q_lock: Lock for message queue
  * @msg_q_state: State of message queue
- * @csr_base: CSR base address
  * @priv: device private data
  */
 struct hfi_info {
@@ -292,7 +288,6 @@ struct hfi_info {
 	bool cmd_q_state;
 	struct mutex msg_q_lock;
 	bool msg_q_state;
-	void __iomem *csr_base;
 	void *priv;
 };
 

+ 33 - 13
drivers/cam_icp/hfi.c

@@ -51,6 +51,16 @@ static void hfi_irq_enable(struct hfi_info *hfi)
 		hfi->ops.irq_enable(hfi->priv);
 }
 
+static void __iomem *hfi_iface_addr(struct hfi_info *hfi)
+{
+	void __iomem *ret = NULL;
+
+	if (hfi->ops.iface_addr)
+		ret = hfi->ops.iface_addr(hfi->priv);
+
+	return IS_ERR_OR_NULL(ret) ? NULL : ret;
+}
+
 void cam_hfi_queue_dump(void)
 {
 	struct hfi_qtbl *qtbl;
@@ -550,12 +560,16 @@ int hfi_get_hw_caps(void *query_buf)
 	return 0;
 }
 
-int cam_hfi_resume(struct hfi_mem_info *hfi_mem, void __iomem *icp_base)
+int cam_hfi_resume(struct hfi_mem_info *hfi_mem)
 {
 	int rc = 0;
 	uint32_t fw_version, status = 0;
+	void __iomem *icp_base = hfi_iface_addr(g_hfi);
 
-	g_hfi->csr_base = icp_base;
+	if (!icp_base) {
+		CAM_ERR(CAM_HFI, "invalid HFI interface address");
+		return -EINVAL;
+	}
 
 	if (readl_poll_timeout(icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE,
 			       status, status == ICP_INIT_RESP_SUCCESS,
@@ -602,15 +616,16 @@ int cam_hfi_resume(struct hfi_mem_info *hfi_mem, void __iomem *icp_base)
 	return rc;
 }
 
-int cam_hfi_init(struct hfi_mem_info *hfi_mem, struct hfi_ops *hfi_ops,
-		void *priv, uint8_t event_driven_mode, void __iomem *icp_base)
+int cam_hfi_init(struct hfi_mem_info *hfi_mem, const struct hfi_ops *hfi_ops,
+		void *priv, uint8_t event_driven_mode)
 {
 	int rc = 0;
+	uint32_t status = 0;
 	struct hfi_qtbl *qtbl;
 	struct hfi_qtbl_hdr *qtbl_hdr;
 	struct hfi_q_hdr *cmd_q_hdr, *msg_q_hdr, *dbg_q_hdr;
-	uint32_t hw_version, fw_version, status = 0;
 	struct sfr_buf *sfr_buffer;
+	void __iomem *icp_base;
 
 	if (!hfi_mem || !hfi_ops || !priv) {
 		CAM_ERR(CAM_HFI,
@@ -752,6 +767,16 @@ int cam_hfi_init(struct hfi_mem_info *hfi_mem, struct hfi_ops *hfi_ops,
 		break;
 	}
 
+	g_hfi->ops = *hfi_ops;
+	g_hfi->priv = priv;
+
+	icp_base = hfi_iface_addr(g_hfi);
+	if (!icp_base) {
+		CAM_ERR(CAM_HFI, "invalid HFI interface address");
+		rc = -EINVAL;
+		goto regions_fail;
+	}
+
 	cam_io_w_mb((uint32_t)hfi_mem->qtbl.iova,
 		icp_base + HFI_REG_QTBL_PTR);
 	cam_io_w_mb((uint32_t)hfi_mem->sfr_buf.iova,
@@ -792,17 +817,12 @@ int cam_hfi_init(struct hfi_mem_info *hfi_mem, struct hfi_ops *hfi_ops,
 		goto regions_fail;
 	}
 
-	hw_version = cam_io_r(icp_base + HFI_REG_A5_HW_VERSION);
-	fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION);
-	CAM_DBG(CAM_HFI, "hw version : : [%x], fw version : [%x]",
-		hw_version, fw_version);
+	CAM_DBG(CAM_HFI, "ICP fw version: 0x%x",
+		cam_io_r(icp_base + HFI_REG_FW_VERSION));
 
-	g_hfi->csr_base = icp_base;
 	g_hfi->hfi_state = HFI_READY;
 	g_hfi->cmd_q_state = true;
 	g_hfi->msg_q_state = true;
-	g_hfi->ops = *hfi_ops;
-	g_hfi->priv = priv;
 
 	hfi_irq_enable(g_hfi);
 
@@ -819,7 +839,7 @@ alloc_fail:
 	return rc;
 }
 
-void cam_hfi_deinit(void __iomem *icp_base)
+void cam_hfi_deinit(void)
 {
 	mutex_lock(&hfi_cmd_q_mutex);
 	mutex_lock(&hfi_msg_q_mutex);

+ 17 - 0
drivers/cam_icp/icp_hw/a5_hw/a5_core.c

@@ -33,6 +33,8 @@
 #define PC_POLL_DELAY_US 100
 #define PC_POLL_TIMEOUT_US 10000
 
+#define A5_GEN_PURPOSE_REG_OFFSET 0x40
+
 static int cam_a5_cpas_vote(struct cam_a5_device_core_info *core_info,
 	struct cam_icp_cpas_vote *cpas_vote)
 {
@@ -513,6 +515,21 @@ void cam_a5_irq_enable(void *priv)
 		ICP_SIERRA_A5_CSR_A2HOSTINTEN);
 }
 
+void __iomem *cam_a5_iface_addr(void *priv)
+{
+	struct cam_hw_info *a5_info = priv;
+	void __iomem *base;
+
+	if (!a5_info) {
+		CAM_ERR(CAM_ICP, "invalid A5 device info");
+		return ERR_PTR(-EINVAL);
+	}
+
+	base = a5_info->soc_info.reg_map[A5_SIERRA_BASE].mem_base;
+
+	return base + A5_GEN_PURPOSE_REG_OFFSET;
+}
+
 int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type,
 	void *cmd_args, uint32_t arg_size)
 {

+ 1 - 0
drivers/cam_icp/icp_hw/a5_hw/a5_core.h

@@ -83,6 +83,7 @@ irqreturn_t cam_a5_irq(int irq_num, void *data);
 
 void cam_a5_irq_raise(void *priv);
 void cam_a5_irq_enable(void *priv);
+void __iomem *cam_a5_iface_addr(void *priv);
 
 /**
  * @brief : API to register a5 hw to platform framework.

+ 16 - 24
drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c

@@ -53,6 +53,12 @@
 
 #define ICP_DEVICE_IDLE_TIMEOUT 400
 
+static const struct hfi_ops hfi_a5_ops = {
+	.irq_raise = cam_a5_irq_raise,
+	.irq_enable = cam_a5_irq_enable,
+	.iface_addr = cam_a5_iface_addr,
+};
+
 static struct cam_icp_hw_mgr icp_hw_mgr;
 
 static void cam_icp_mgr_process_dbg_buf(unsigned int debug_lvl);
@@ -3118,17 +3124,8 @@ static int cam_icp_mgr_icp_power_collapse(struct cam_icp_hw_mgr *hw_mgr)
 
 static int cam_icp_mgr_hfi_resume(struct cam_icp_hw_mgr *hw_mgr)
 {
-	struct cam_hw_intf *a5_dev_intf = NULL;
-	struct cam_hw_info *a5_dev = NULL;
 	struct hfi_mem_info hfi_mem;
 
-	a5_dev_intf = hw_mgr->a5_dev_intf;
-	if (!a5_dev_intf) {
-		CAM_ERR(CAM_ICP, "a5_dev_intf is invalid\n");
-		return -EINVAL;
-	}
-	a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
-
 	hfi_mem.qtbl.kva = icp_hw_mgr.hfi_mem.qtbl.kva;
 	hfi_mem.qtbl.iova = icp_hw_mgr.hfi_mem.qtbl.iova;
 	hfi_mem.qtbl.len = icp_hw_mgr.hfi_mem.qtbl.len;
@@ -3203,8 +3200,7 @@ static int cam_icp_mgr_hfi_resume(struct cam_icp_hw_mgr *hw_mgr)
 		hfi_mem.io_mem2.iova,
 		hfi_mem.io_mem2.len);
 
-	return cam_hfi_resume(&hfi_mem,
-		a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
+	return cam_hfi_resume(&hfi_mem);
 }
 
 static int cam_icp_retry_wait_for_abort(
@@ -3479,7 +3475,6 @@ static int cam_icp_mgr_hw_close(void *hw_priv, void *hw_close_args)
 {
 	struct cam_icp_hw_mgr *hw_mgr = hw_priv;
 	struct cam_hw_intf *a5_dev_intf = NULL;
-	struct cam_hw_info *a5_dev = NULL;
 	struct cam_icp_a5_set_irq_cb irq_cb;
 	struct cam_icp_a5_set_fw_buf_info fw_buf_info;
 	int rc = 0;
@@ -3494,7 +3489,7 @@ static int cam_icp_mgr_hw_close(void *hw_priv, void *hw_close_args)
 		CAM_DBG(CAM_ICP, "a5_dev_intf is NULL");
 		return -EINVAL;
 	}
-	a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
+
 	fw_buf_info.kva = 0;
 	fw_buf_info.iova = 0;
 	fw_buf_info.len = 0;
@@ -3505,8 +3500,9 @@ static int cam_icp_mgr_hw_close(void *hw_priv, void *hw_close_args)
 		sizeof(fw_buf_info));
 	if (rc)
 		CAM_ERR(CAM_ICP, "nullify the fw buf failed");
-	cam_hfi_deinit(
-		a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
+
+	cam_hfi_deinit();
+
 	irq_cb.icp_hw_mgr_cb = NULL;
 	irq_cb.data = NULL;
 	rc = a5_dev_intf->hw_ops.process_cmd(
@@ -3624,7 +3620,7 @@ static int cam_icp_mgr_hfi_init(struct cam_icp_hw_mgr *hw_mgr)
 	struct cam_hw_intf *a5_dev_intf = NULL;
 	struct cam_hw_info *a5_dev = NULL;
 	struct hfi_mem_info hfi_mem;
-	struct hfi_ops hfi_ops;
+	const struct hfi_ops *hfi_ops;
 
 	a5_dev_intf = hw_mgr->a5_dev_intf;
 	if (!a5_dev_intf) {
@@ -3689,11 +3685,9 @@ static int cam_icp_mgr_hfi_init(struct cam_icp_hw_mgr *hw_mgr)
 		hfi_mem.io_mem2.len = 0x0;
 	}
 
-	hfi_ops.irq_raise = cam_a5_irq_raise;
-	hfi_ops.irq_enable = cam_a5_irq_enable;
+	hfi_ops = &hfi_a5_ops;
 
-	return cam_hfi_init(&hfi_mem, &hfi_ops, a5_dev, 0,
-			a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
+	return cam_hfi_init(&hfi_mem, hfi_ops, a5_dev, 0);
 }
 
 static int cam_icp_mgr_send_fw_init(struct cam_icp_hw_mgr *hw_mgr)
@@ -3807,7 +3801,6 @@ hw_deinit:
 static int cam_icp_mgr_hw_open(void *hw_mgr_priv, void *download_fw_args)
 {
 	struct cam_hw_intf *a5_dev_intf = NULL;
-	struct cam_hw_info *a5_dev = NULL;
 	struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
 	bool icp_pc = false;
 	int rc = 0;
@@ -3827,7 +3820,7 @@ static int cam_icp_mgr_hw_open(void *hw_mgr_priv, void *download_fw_args)
 		CAM_ERR(CAM_ICP, "a5_dev_intf is invalid");
 		return -EINVAL;
 	}
-	a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
+
 	rc = cam_icp_allocate_hfi_mem();
 	if (rc)
 		goto alloc_hfi_mem_failed;
@@ -3873,8 +3866,7 @@ static int cam_icp_mgr_hw_open(void *hw_mgr_priv, void *download_fw_args)
 	return rc;
 
 fw_init_failed:
-	cam_hfi_deinit(
-		a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
+	cam_hfi_deinit();
 hfi_init_failed:
 	cam_icp_mgr_proc_suspend(hw_mgr);
 fw_download_failed: