Jelajahi Sumber

ubwcp: r2 support and other misc changes

- Program height in bytes for non-v1 hardware
- Additional error checking at various places
  to prevent regulator call with NULL vdd
- Set_ops fails when we do rmmod and then insmod
  ignore the return value so we can successfully insmod
  This is a hack that needs to be removed for final product

Change-Id: Ib0252d7ddb7fa34aeeea7b1e1e3f81216e0cc5d3
Signed-off-by: Amol Jadi <[email protected]>
Amol Jadi 2 tahun lalu
induk
melakukan
010a4acc07
3 mengubah file dengan 87 tambahan dan 29 penghapusan
  1. 59 23
      ubwcp/ubwcp.c
  2. 27 5
      ubwcp/ubwcp_hw.c
  3. 1 1
      ubwcp/ubwcp_hw.h

+ 59 - 23
ubwcp/ubwcp.c

@@ -53,7 +53,7 @@ MODULE_IMPORT_NS(DMA_BUF);
 				} while (0)
 #define ERR(fmt, args...) pr_err("ubwcp: %s(): ~~~ERROR~~~: " fmt "\n", __func__, ##args)
 
-#define FENTRY() DBG("ubwcp: %s()", __func__)
+#define FENTRY() DBG("")
 
 
 #define META_DATA_PITCH_ALIGN    64
@@ -225,6 +225,16 @@ static int ubwcp_power(struct ubwcp_driver *ubwcp, bool enable)
 {
 	int ret = 0;
 
+	if (!ubwcp) {
+		ERR("ubwcp ptr is NULL");
+		return -1;
+	}
+
+	if (!ubwcp->vdd) {
+		ERR("vdd is NULL");
+		return -1;
+	}
+
 	if (enable) {
 		ret = regulator_enable(ubwcp->vdd);
 		if (ret < 0) {
@@ -1363,7 +1373,14 @@ int ubwcp_set_buf_attrs(struct dma_buf *dmabuf, struct ubwcp_buffer_attrs *attr)
 	mmdata->metadata_base_uv = PAGE_ADDR(iova_base + metadata_p0 + pixeldata_p0);
 	mmdata->buffer_y_offset  = PAGE_ADDR(metadata_p0);
 	mmdata->buffer_uv_offset = PAGE_ADDR(metadata_p1);
-	mmdata->width_height     = width_b << 16 | height_b;
+
+	/* NOTE: For version 1.1, both width & height needs to be in bytes.
+	 * For other versions, width in bytes & height in pixels.
+	 */
+	if ((ubwcp->hw_ver_major == 1) && (ubwcp->hw_ver_minor == 1))
+		mmdata->width_height = width_b << 16 | height_b;
+	else
+		mmdata->width_height = width_b << 16 | attr->height;
 
 	print_mmdata_desc(mmdata);
 
@@ -1583,6 +1600,7 @@ err:
  */
 static int unlock_internal(struct ubwcp_buf *buf, enum dma_data_direction dir, bool free_buffer)
 {
+	int ret = 0;
 	struct ubwcp_driver *ubwcp;
 
 	DBG("current lock_count: %d", buf->lock_count);
@@ -1606,16 +1624,16 @@ static int unlock_internal(struct ubwcp_buf *buf, enum dma_data_direction dir, b
 	/* TODO: Use flush work around, remove when no longer needed */
 	ubwcp_flush_cache_wa(ubwcp->dev, buf->ula_pa, buf->ula_size);
 
-	/* TBD: confirm with HW if this should be done before or
-	 * after disable_range_ck()
-	 */
-	ubwcp_flush(ubwcp);
-
-	/* disable range check */
+	/* disable range check with ubwcp flush */
 	DBG("disabling range check");
+	//TBD: could combine these 2 locks into a single lock to make it simpler
+	mutex_lock(&ubwcp->ubwcp_flush_lock);
 	mutex_lock(&ubwcp->hw_range_ck_lock);
-	ubwcp_hw_disable_range_check(ubwcp->base, buf->desc->idx);
+	ret = ubwcp_hw_disable_range_check_with_flush(ubwcp->base, buf->desc->idx);
+	if (ret)
+		ERR("disable_range_check_with_flush() failed: %d", ret);
 	mutex_unlock(&ubwcp->hw_range_ck_lock);
+	mutex_unlock(&ubwcp->ubwcp_flush_lock);
 
 	/* release descriptor if perm range xlation is not set */
 	if (!buf->perm) {
@@ -1623,7 +1641,7 @@ static int unlock_internal(struct ubwcp_buf *buf, enum dma_data_direction dir, b
 		buf->desc = NULL;
 	}
 	buf->locked = false;
-	return 0;
+	return ret;
 }
 
 
@@ -2146,10 +2164,10 @@ static int qcom_ubwcp_probe(struct platform_device *pdev)
 
 	/* Regulator */
 	ubwcp->vdd = devm_regulator_get(ubwcp_dev, "vdd");
-	if (IS_ERR(ubwcp->vdd)) {
+	if (IS_ERR_OR_NULL(ubwcp->vdd)) {
 		ret = PTR_ERR(ubwcp->vdd);
 		ERR("devm_regulator_get() failed: %d", ret);
-		return ret;
+		return -1;
 	}
 
 	mutex_init(&ubwcp->desc_lock);
@@ -2193,10 +2211,7 @@ static int qcom_ubwcp_probe(struct platform_device *pdev)
 	/* one time hw init */
 	ubwcp_hw_one_time_init(ubwcp->base);
 	ubwcp_hw_version(ubwcp->base, &ubwcp->hw_ver_major, &ubwcp->hw_ver_minor);
-	DBG("read version: major %d, minor %d",
-				ubwcp->hw_ver_major, ubwcp->hw_ver_minor);
-
-
+	pr_err("ubwcp: hw version: major %d, minor %d\n", ubwcp->hw_ver_major, ubwcp->hw_ver_minor);
 	if (ubwcp->hw_ver_major == 0) {
 		ERR("Failed to read HW version");
 		ret = -1;
@@ -2205,7 +2220,6 @@ static int qcom_ubwcp_probe(struct platform_device *pdev)
 
 	/* set pdev->dev->driver_data = ubwcp */
 	platform_set_drvdata(pdev, ubwcp);
-	me = ubwcp;
 
 	/* enable all 4 interrupts */
 	ubwcp_hw_interrupt_enable(ubwcp->base, INTERRUPT_READ_ERROR,   true);
@@ -2221,11 +2235,17 @@ static int qcom_ubwcp_probe(struct platform_device *pdev)
 
 	ret = msm_ubwcp_set_ops(ubwcp_init_buffer, ubwcp_free_buffer, ubwcp_lock, ubwcp_unlock);
 	if (ret) {
-		ERR("msm_ubwcp_set_ops() failed: %d", ret);
-		goto err_power_off;
+		ERR("msm_ubwcp_set_ops() failed: %d, but IGNORED", ret);
+		/* TBD: ignore return error during testing phase.
+		 * This allows us to rmmod/insmod for faster dev cycle.
+		 * In final version: return error and de-register driver if set_ops fails.
+		 */
+		ret = 0;
+		//goto err_power_off;
 	} else {
 		DBG("msm_ubwcp_set_ops(): success"); }
 
+	me = ubwcp;
 	return ret;
 
 err_power_off:
@@ -2237,7 +2257,6 @@ err_pool_add:
 	gen_pool_destroy(ubwcp->ula_pool);
 err_pool_create:
 	ubwcp_cdev_deinit(ubwcp);
-
 	return ret;
 }
 
@@ -2297,14 +2316,31 @@ static int ubwcp_probe_cb_desc(struct platform_device *pdev)
 	DBG("desc_base = %p size = %zu", ubwcp->buffer_desc_base,
 						ubwcp->buffer_desc_size);
 
-	//TBD:
-	ubwcp_power(ubwcp, true);
+	ret = ubwcp_power(ubwcp, true);
+	if (ret) {
+		ERR("failed to power on");
+		goto err;
+	}
 	ubwcp_hw_set_buf_desc(ubwcp->base, (u64) ubwcp->buffer_desc_dma_handle,
 						UBWCP_BUFFER_DESC_OFFSET);
 
-	ubwcp_power(ubwcp, false);
+	ret = ubwcp_power(ubwcp, false);
+	if (ret) {
+		ERR("failed to power off");
+		goto err;
+	}
 
 	return ret;
+
+err:
+	dma_free_coherent(ubwcp->dev_desc_cb,
+				ubwcp->buffer_desc_size,
+				ubwcp->buffer_desc_base,
+				ubwcp->buffer_desc_dma_handle);
+	ubwcp->buffer_desc_base = NULL;
+	ubwcp->buffer_desc_dma_handle = 0;
+	ubwcp->dev_desc_cb = NULL;
+	return -1;
 }
 
 /* buffer context bank device remove */

+ 27 - 5
ubwcp/ubwcp_hw.c

@@ -224,16 +224,38 @@ void ubwcp_hw_enable_range_check(void __iomem *base, u16 index)
 }
 EXPORT_SYMBOL(ubwcp_hw_enable_range_check);
 
-void ubwcp_hw_disable_range_check(void __iomem *base, u16 index)
+
+/* Disable range check with flush */
+int ubwcp_hw_disable_range_check_with_flush(void __iomem *base, u16 index)
 {
+	u32 flush_complete = 0;
+	u32 count = 20;
 	u32 val;
 	u16 ctrl_reg = index >> 5;
 
-	val = UBWCP_REG_READ(base, RANGE_CHECK_CONTROL + ctrl_reg*4);
-	val &= ~(1 << (index & 0x1F));
-	UBWCP_REG_WRITE(base, RANGE_CHECK_CONTROL + ctrl_reg*4, val);
+	//assert flush
+	UBWCP_REG_WRITE(base, FLUSH_CONTROL, 0x3);
+
+	//poll for flush done
+	do {
+		flush_complete = UBWCP_REG_READ(base, FLUSH_STATUS) & 0x1;
+		if (flush_complete) {
+			//disable range ck
+			val = UBWCP_REG_READ(base, RANGE_CHECK_CONTROL + ctrl_reg*4);
+			val &= ~(1 << (index & 0x1F));
+			UBWCP_REG_WRITE(base, RANGE_CHECK_CONTROL + ctrl_reg*4, val);
+
+			//clear flush
+			UBWCP_REG_WRITE(base, FLUSH_CONTROL, 0x0);
+			return 0;
+		}
+		udelay(100);
+	} while (count--);
+
+	ERR("~~~~~ FLUSH FAILED ~~~~~");
+	return -1;
 }
-EXPORT_SYMBOL(ubwcp_hw_disable_range_check);
+EXPORT_SYMBOL(ubwcp_hw_disable_range_check_with_flush);
 
 void ubwcp_hw_set_buf_desc(void __iomem *base, u64 desc_addr, u16 desc_stride)
 {

+ 1 - 1
ubwcp/ubwcp_hw.h

@@ -58,7 +58,7 @@ struct __packed ubwcp_hw_meta_metadata {
 void ubwcp_hw_version(void __iomem *base, u32 *major, u32 *minor);
 void ubwcp_hw_set_buf_desc(void __iomem *base, u64 desc_addr, u16 desc_stride);
 void ubwcp_hw_enable_range_check(void __iomem *base, u16 index);
-void ubwcp_hw_disable_range_check(void __iomem *base, u16 index);
+int ubwcp_hw_disable_range_check_with_flush(void __iomem *base, u16 index);
 void ubwcp_hw_set_range_check(void __iomem *base, u16 index, phys_addr_t pa, size_t size);
 u64 ubwcp_hw_interrupt_src_address(void __iomem *base, u16 interrupt);
 void ubwcp_hw_interrupt_clear(void __iomem *base, u16 interrupt);