int cx18_firmware_init(struct cx18 *cx) { /* Allow chip to control CLKRUN */ write_reg(0x5, CX18_DSP0_INTERRUPT_MASK); write_reg(0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */ cx18_msleep_timeout(1, 0); sw1_irq_enable(IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); sw2_irq_enable(IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); /* Only if the processor is not running */ if (read_reg(CX18_PROC_SOFT_RESET) & 8) { int sz = load_apu_fw_direct("v4l-cx23418-apu.fw", cx->enc_mem, cx, CX18_FW_APU_SIZE); sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw", cx->enc_mem, cx, CX18_FW_CPU_SIZE); if (sz > 0) { int retries = 0; /* start the CPU */ write_reg(0x00080000, CX18_PROC_SOFT_RESET); while (retries++ < 50) { /* Loop for max 500mS */ if ((read_reg(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; } /* initialize GPIO */ write_reg(0x14001400, 0xC78110); return 0; }
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); /* Stop the firmware */ cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET, 0x0000000F, 0x000F000F); 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); 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 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; }