V4L/DVB (8165): cx18: fix v4l-cx23418-dig.fw firmware load.
authorHans Verkuil <hverkuil@xs4all.nl>
Sat, 28 Jun 2008 11:03:02 +0000 (08:03 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Sun, 20 Jul 2008 10:15:13 +0000 (07:15 -0300)
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
drivers/media/video/cx18/cx18-av-firmware.c

index a1a6af6c1c8f5888a83432b35bbf4d5b69bac2fe..ab86dc71bf8d595fcfce043d06d4ee9019c144d5 100644 (file)
@@ -31,40 +31,58 @@ int cx18_av_loadfw(struct cx18 *cx)
        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 */
-
-       /* 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);
-
-       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 (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))
+       /* 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);
+
+               /* Put the 8051 in reset and enable firmware upload */
+               cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000);
+
+               ptr = fw->data;
+               size = fw->size;
+
+               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);
+                               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);