int isp_init(struct bcwc_private *dev_priv) { u32 num_channels, queue_size; u32 reg; int i, retries; isp_load_firmware(dev_priv); isp_acpi_set_power(dev_priv, 1); mdelay(20); /* OSX driver configures the PCI bus here but we ignore it */ pci_set_power_state(dev_priv->pdev, PCI_D0); isp_enable_sensor(dev_priv); BCWC_ISP_REG_WRITE(0, ISP_IPC_NUM_CHAN); bcwc_hw_pci_post(dev_priv); BCWC_ISP_REG_WRITE(0, ISP_IPC_QUEUE_SIZE); bcwc_hw_pci_post(dev_priv); BCWC_ISP_REG_WRITE(0, ISP_REG_C3008); bcwc_hw_pci_post(dev_priv); BCWC_ISP_REG_WRITE(0, ISP_FW_HEAP_SIZE); bcwc_hw_pci_post(dev_priv); BCWC_ISP_REG_WRITE(0, ISP_REG_C3010); bcwc_hw_pci_post(dev_priv); BCWC_ISP_REG_WRITE(0, ISP_REG_C3014); bcwc_hw_pci_post(dev_priv); BCWC_ISP_REG_WRITE(0, ISP_REG_C3018); bcwc_hw_pci_post(dev_priv); BCWC_ISP_REG_WRITE(0, ISP_REG_C301C); bcwc_hw_pci_post(dev_priv); BCWC_ISP_REG_WRITE(0xffffffff, ISP_REG_41024); bcwc_hw_pci_post(dev_priv); /* * Probably the IPC queue * FIXME: Check if we can do 64bit writes on PCIe */ for (i = ISP_IPC_CHAN_START; i <= ISP_IPC_CHAN_END; i += 8) { BCWC_ISP_REG_WRITE(0xffffffff, i); BCWC_ISP_REG_WRITE(0, i + 4); } bcwc_hw_pci_post(dev_priv); BCWC_ISP_REG_WRITE( 0x80000000, ISP_REG_40008); bcwc_hw_pci_post(dev_priv); BCWC_ISP_REG_WRITE(0x1, ISP_REG_40004); bcwc_hw_pci_post(dev_priv); for (retries = 0; retries < 1000; retries++) { reg = BCWC_ISP_REG_READ(ISP_REG_41000); if ((reg & 0xf0) > 0) break; mdelay(10); } if (retries >= 1000) { dev_info(&dev_priv->pdev->dev, "Init failed! No wake signal\n"); return -EIO; } dev_info(&dev_priv->pdev->dev, "ISP woke up after %dms\n", (retries - 1) * 10); BCWC_ISP_REG_WRITE(0xffffffff, ISP_REG_41024); num_channels = BCWC_ISP_REG_READ(ISP_IPC_NUM_CHAN) + 1; queue_size = BCWC_ISP_REG_READ(ISP_IPC_QUEUE_SIZE); dev_info(&dev_priv->pdev->dev, "Number of IPC channels: %u, queue size: %u\n", num_channels, queue_size); if (num_channels > 32) { dev_info(&dev_priv->pdev->dev, "Too many IPC channels: %u\n", num_channels); return -EIO; } /* bcwc_alloc_dev_mem(queue_size, &ret, 0); */ /* Firmware must fit in 4194304 bytes */ reg = BCWC_ISP_REG_READ(ISP_FW_HEAP_SIZE); if (reg > 0x400000) { dev_info(&dev_priv->pdev->dev, "Firmware request size too big (%u bytes)\n", reg); return -ENOMEM; } dev_info(&dev_priv->pdev->dev, "Firmware request size: %u\n", reg); return 0; }
int isp_init(struct fthd_private *dev_priv) { struct isp_mem_obj *fw_queue, *heap, *fw_args; struct isp_fw_args fw_args_data; u32 num_channels, queue_size, heap_size, reg, offset; int i, retries, ret; ret = isp_mem_init(dev_priv); if (ret) return ret; ret = isp_load_firmware(dev_priv); if (ret) return ret; isp_acpi_set_power(dev_priv, 1); mdelay(20); pci_set_power_state(dev_priv->pdev, PCI_D0); mdelay(10); isp_enable_sensor(dev_priv); FTHD_ISP_REG_WRITE(0, ISP_FW_CHAN_CTRL); FTHD_ISP_REG_WRITE(0, ISP_FW_QUEUE_CTRL); FTHD_ISP_REG_WRITE(0, ISP_FW_SIZE); FTHD_ISP_REG_WRITE(0, ISP_FW_HEAP_SIZE); FTHD_ISP_REG_WRITE(0, ISP_FW_HEAP_ADDR); FTHD_ISP_REG_WRITE(0, ISP_FW_HEAP_SIZE2); FTHD_ISP_REG_WRITE(0, ISP_REG_C3018); FTHD_ISP_REG_WRITE(0, ISP_REG_C301C); FTHD_ISP_REG_WRITE(0xffffffff, ISP_IRQ_CLEAR); /* * Probably the IPC queue * FIXME: Check if we can do 64bit writes on PCIe */ for (i = ISP_FW_CHAN_START; i <= ISP_FW_CHAN_END; i += 8) { FTHD_ISP_REG_WRITE(0xffffffff, i); FTHD_ISP_REG_WRITE(0, i + 4); } FTHD_ISP_REG_WRITE(0x80000000, ISP_REG_40008); FTHD_ISP_REG_WRITE(0x1, ISP_REG_40004); for (retries = 0; retries < 1000; retries++) { reg = FTHD_ISP_REG_READ(ISP_IRQ_STATUS); if ((reg & 0xf0) > 0) break; mdelay(10); } if (retries >= 1000) { dev_info(&dev_priv->pdev->dev, "Init failed! No wake signal\n"); return -EIO; } dev_info(&dev_priv->pdev->dev, "ISP woke up after %dms\n", (retries - 1) * 10); FTHD_ISP_REG_WRITE(0xffffffff, ISP_IRQ_CLEAR); num_channels = FTHD_ISP_REG_READ(ISP_FW_CHAN_CTRL); queue_size = FTHD_ISP_REG_READ(ISP_FW_QUEUE_CTRL) + 1; dev_info(&dev_priv->pdev->dev, "Number of IPC channels: %u, queue size: %u\n", num_channels, queue_size); if (num_channels > 32) { dev_info(&dev_priv->pdev->dev, "Too many IPC channels: %u\n", num_channels); return -EIO; } fw_queue = isp_mem_create(dev_priv, FTHD_MEM_FW_QUEUE, queue_size); if (!fw_queue) return -ENOMEM; /* Firmware heap max size is 4mb */ heap_size = FTHD_ISP_REG_READ(ISP_FW_HEAP_SIZE); if (heap_size == 0) { FTHD_ISP_REG_WRITE(0, ISP_FW_CHAN_CTRL); FTHD_ISP_REG_WRITE(fw_queue->offset, ISP_FW_QUEUE_CTRL); FTHD_ISP_REG_WRITE(dev_priv->firmware->size_aligned, ISP_FW_SIZE); FTHD_ISP_REG_WRITE(0x10000000 - dev_priv->firmware->size_aligned, ISP_FW_HEAP_SIZE); FTHD_ISP_REG_WRITE(0, ISP_FW_HEAP_ADDR); FTHD_ISP_REG_WRITE(0, ISP_FW_HEAP_SIZE2); } else { /* Must be at least 0x1000 bytes */ heap_size = (heap_size < 0x1000) ? 0x1000 : heap_size; if (heap_size > 0x400000) { dev_info(&dev_priv->pdev->dev, "Firmware heap request size too big (%ukb)\n", heap_size / 1024); return -ENOMEM; } dev_info(&dev_priv->pdev->dev, "Firmware requested heap size: %ukb\n", heap_size / 1024); heap = isp_mem_create(dev_priv, FTHD_MEM_HEAP, heap_size); if (!heap) return -ENOMEM; FTHD_ISP_REG_WRITE(0, ISP_FW_CHAN_CTRL); /* Set IPC queue base addr */ FTHD_ISP_REG_WRITE(fw_queue->offset, ISP_FW_QUEUE_CTRL); FTHD_ISP_REG_WRITE(FTHD_MEM_FW_SIZE, ISP_FW_SIZE); FTHD_ISP_REG_WRITE(0x10000000 - FTHD_MEM_FW_SIZE, ISP_FW_HEAP_SIZE); FTHD_ISP_REG_WRITE(heap->offset, ISP_FW_HEAP_ADDR); FTHD_ISP_REG_WRITE(heap->size, ISP_FW_HEAP_SIZE2); /* Set FW args */ fw_args = isp_mem_create(dev_priv, FTHD_MEM_FW_ARGS, sizeof(struct isp_fw_args)); if (!fw_args) return -ENOMEM; FTHD_S2_MEMCPY_TOIO(fw_args->offset, &fw_args_data, sizeof(fw_args_data)); fw_args_data.__unknown = 2; fw_args_data.fw_arg = 0; fw_args_data.full_stats_mode = 0; FTHD_ISP_REG_WRITE(fw_args->offset, ISP_REG_C301C); FTHD_ISP_REG_WRITE(0x10, ISP_REG_41020); for (retries = 0; retries < 1000; retries++) { reg = FTHD_ISP_REG_READ(ISP_IRQ_STATUS); if ((reg & 0xf0) > 0) break; mdelay(10); } if (retries >= 1000) { dev_info(&dev_priv->pdev->dev, "Init failed! No second int\n"); return -EIO; } /* FIXME: free on error path */ dev_info(&dev_priv->pdev->dev, "ISP second int after %dms\n", (retries - 1) * 10); offset = FTHD_ISP_REG_READ(ISP_FW_CHAN_CTRL); dev_info(&dev_priv->pdev->dev, "Channel description table at %08x\n", offset); ret = isp_fill_channel_info(dev_priv, offset, num_channels); if (ret) return ret; fthd_channel_ringbuf_init(dev_priv, dev_priv->channel_terminal); fthd_channel_ringbuf_init(dev_priv, dev_priv->channel_io); fthd_channel_ringbuf_init(dev_priv, dev_priv->channel_debug); fthd_channel_ringbuf_init(dev_priv, dev_priv->channel_buf_h2t); fthd_channel_ringbuf_init(dev_priv, dev_priv->channel_buf_t2h); fthd_channel_ringbuf_init(dev_priv, dev_priv->channel_shared_malloc); fthd_channel_ringbuf_init(dev_priv, dev_priv->channel_io_t2h); FTHD_ISP_REG_WRITE(0x8042006, ISP_FW_HEAP_SIZE); for (retries = 0; retries < 1000; retries++) { reg = FTHD_ISP_REG_READ(ISP_FW_HEAP_SIZE); if (!reg) break; mdelay(10); } if (retries >= 1000) { dev_info(&dev_priv->pdev->dev, "Init failed! No magic value\n"); isp_uninit(dev_priv); return -EIO; } /* FIXME: free on error path */ dev_info(&dev_priv->pdev->dev, "magic value: %08x after %d ms\n", reg, (retries - 1) * 10); } return 0; }