int cx18_firmware_init(struct cx18 *cx)
 {
+       u32 fw_entry_addr;
+       int sz, retries;
+       u32 api_args[MAX_MB_ARGUMENTS];
+
        /* Allow chip to control CLKRUN */
        cx18_write_reg(cx, 0x5, CX18_DSP0_INTERRUPT_MASK);
 
 
        cx18_msleep_timeout(1, 0);
 
+       /* If the CPU is still running */
+       if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 8) == 0) {
+               CX18_ERR("%s: couldn't stop CPU to load firmware\n", __func__);
+               return -EIO;
+       }
+
        cx18_sw1_irq_enable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
        cx18_sw2_irq_enable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
 
-       /* Only if the processor is not running */
-       if (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 8) {
-               u32 fw_entry_addr = 0;
-               int sz = load_apu_fw_direct("v4l-cx23418-apu.fw",
-                              cx->enc_mem, cx, &fw_entry_addr);
-
-               if (sz <= 0)
-                       return sz;
-
-               /* Clear bit0 for APU to start from 0 */
-               cx18_write_reg(cx, cx18_read_reg(cx, 0xc72030) & ~1, 0xc72030);
-
-               cx18_write_enc(cx, 0xE51FF004, 0);    /* ldr pc, [pc, #-4] */
-               cx18_write_enc(cx, fw_entry_addr, 4);
-
-               /* Start APU */
-               cx18_write_reg_expect(cx, 0x00010000, CX18_PROC_SOFT_RESET,
-                                         0x00000000, 0x00010001);
-               cx18_msleep_timeout(500, 0);
-
-               sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw",
-                                       cx->enc_mem, cx);
-
-               if (sz > 0) {
-                       int retries = 0;
-
-                       /* start the CPU */
-                       cx18_write_reg_expect(cx,
-                                             0x00080000, CX18_PROC_SOFT_RESET,
-                                             0x00000000, 0x00080008);
-                       while (retries++ < 50) { /* Loop for max 500mS */
-                               if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET)
-                                    & 1) == 0)
-                                       break;
-                               cx18_msleep_timeout(10, 0);
-                       }
-                       cx18_msleep_timeout(200, 0);
-                       if (retries == 51) {
-                               CX18_ERR("Could not start the CPU\n");
-                               return -EIO;
-                       }
-               }
-               if (sz <= 0)
-                       return -EIO;
+       sz = load_cpu_fw_direct("v4l-cx23418-cpu.fw", cx->enc_mem, cx);
+       if (sz <= 0)
+               return sz;
+
+       /* The SCB & IPC area *must* be correct before starting the firmwares */
+       cx18_init_scb(cx);
+
+       fw_entry_addr = 0;
+       sz = load_apu_fw_direct("v4l-cx23418-apu.fw", cx->enc_mem, cx,
+                               &fw_entry_addr);
+       if (sz <= 0)
+               return sz;
+
+       /* Start the CPU. The CPU will take care of the APU for us. */
+       cx18_write_reg_expect(cx, 0x00080000, CX18_PROC_SOFT_RESET,
+                                 0x00000000, 0x00080008);
+
+       /* Wait up to 500 ms for the APU to come out of reset */
+       for (retries = 0;
+            retries < 50 && (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1;
+            retries++)
+               cx18_msleep_timeout(10, 0);
+
+       cx18_msleep_timeout(200, 0);
+
+       if (retries == 50 &&
+           (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1) {
+               CX18_ERR("Could not start the CPU\n");
+               return -EIO;
        }
 
        /*
-        * The CPU firmware apparently sets up to receive an interrupt for it's
-        * outgoing IRQ_CPU_TO_EPU_ACK to us (*boggle*).  We get an interrupt
-        * when it sends us an ack, but by the time we process it, that flag in
-        * the SW2 status register has been cleared by the CPU firmware.
-        * We'll prevent that not so useful behavior by clearing the CPU's
-        * interrupt enables for Ack IRQ's we want to process.
+        * The CPU had once before set up to receive an interrupt for it's
+        * outgoing IRQ_CPU_TO_EPU_ACK to us.  If it ever does this, we get an
+        * interrupt when it sends us an ack, but by the time we process it,
+        * that flag in the SW2 status register has been cleared by the CPU
+        * firmware.  We'll prevent that not so useful condition from happening
+        * by clearing the CPU's interrupt enables for Ack IRQ's we want to
+        * process.
         */
        cx18_sw2_irq_disable_cpu(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
 
+       /* Try a benign command to see if the CPU is alive and well */
+       sz = cx18_vapi_result(cx, api_args, CX18_CPU_DEBUG_PEEK32, 1, 0);
+       if (sz < 0)
+               return sz;
+
        /* initialize GPIO */
        cx18_write_reg_expect(cx, 0x14001400, 0xc78110, 0x00001400, 0x14001400);
        return 0;