V4L/DVB (8165): cx18: fix v4l-cx23418-dig.fw firmware load.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c
index a1a6af6..ab86dc7 100644
--- a/drivers/media/video/cx18/cx18-av-firmware.c
+++ b/drivers/media/video/cx18/cx18-av-firmware.c
@@ -31,40 +31,58 @@
 	u32 v;
 	const u8 *ptr;
 	int i;
+	int retries = 0;
 
 	if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) {
 		CX18_ERR("unable to open firmware %s\n", FWFILE);
 		return -EINVAL;
 	}
 
-	cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000);
-	cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6); /* Byte 0 */
+	/* The firmware load often has byte errors, so allow for several
+	   retries, both at byte level and at the firmware load level. */
+	while (retries < 5) {
+		cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000);
+		cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6);
 
-	/* Reset the Mako core (Register is undocumented.) */
-	cx18_av_write4(cx, 0x8100, 0x00010000);
+		/* Reset the Mako core (Register is undocumented.) */
+		cx18_av_write4(cx, 0x8100, 0x00010000);
 
-	/* Put the 8051 in reset and enable firmware upload */
-	cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000);
+		/* Put the 8051 in reset and enable firmware upload */
+		cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000);
 
-	ptr = fw->data;
-	size = fw->size;
+		ptr = fw->data;
+		size = fw->size;
 
-	for (i = 0; i < size; i++) {
-		u32 dl_control = 0x0F000000 | ((u32)ptr[i] << 16);
-		u32 value = 0;
-		int retries;
+		for (i = 0; i < size; i++) {
+			u32 dl_control = 0x0F000000 | i | ((u32)ptr[i] << 16);
+			u32 value = 0;
+			int retries;
 
-		for (retries = 0; retries < 5; retries++) {
-			cx18_av_write4(cx, CXADEC_DL_CTL, dl_control);
-			value = cx18_av_read4(cx, CXADEC_DL_CTL);
-			if ((value & 0x3F00) == (dl_control & 0x3F00))
+			for (retries = 0; retries < 5; retries++) {
+				cx18_av_write4(cx, CXADEC_DL_CTL, dl_control);
+				udelay(10);
+				value = cx18_av_read4(cx, CXADEC_DL_CTL);
+				if (value == dl_control)
+					break;
+				/* Check if we can correct the byte by changing
+				   the address.  We can only write the lower
+				   address byte of the address. */
+				if ((value & 0x3F00) != (dl_control & 0x3F00)) {
+					retries = 5;
+					break;
+				}
+			}
+			if (retries >= 5)
 				break;
 		}
-		if (retries >= 5) {
-			CX18_ERR("unable to load firmware %s\n", FWFILE);
-			release_firmware(fw);
-			return -EIO;
-		}
+		if (i == size)
+			break;
+		retries++;
+	}
+	if (retries >= 5) {
+		CX18_ERR("unable to load firmware %s\n", FWFILE);
+		release_firmware(fw);
+		return -EIO;
 	}
 
 	cx18_av_write4(cx, CXADEC_DL_CTL, 0x13000000 | fw->size);