static int isp_load_firmware(struct fthd_private *dev_priv) { const struct firmware *fw; int ret = 0; ret = request_firmware(&fw, "facetimehd/firmware.bin", &dev_priv->pdev->dev); if (ret) return ret; /* Firmware memory is preallocated at init time */ if (!dev_priv->firmware) return -ENOMEM; if (dev_priv->firmware->base.start != dev_priv->mem->start) { dev_err(&dev_priv->pdev->dev, "Misaligned firmware memory object (offset: %lu)\n", dev_priv->firmware->offset); isp_mem_destroy(dev_priv->firmware); dev_priv->firmware = NULL; return -EBUSY; } FTHD_S2_MEMCPY_TOIO(dev_priv->firmware->offset, fw->data, fw->size); /* Might need a flush here if we map ISP memory cached */ dev_info(&dev_priv->pdev->dev, "Loaded firmware, size: %lukb\n", fw->size / 1024); release_firmware(fw); return ret; }
static int fthd_send_h2t_buffer(struct fthd_private *dev_priv, struct h2t_buf_ctx *ctx) { u32 entry; int ret; pr_debug("sending buffer %p size %ld, ctx %p\n", ctx->vb, sizeof(ctx->dma_desc_list), ctx); FTHD_S2_MEMCPY_TOIO(ctx->dma_desc_obj->offset, &ctx->dma_desc_list, sizeof(ctx->dma_desc_list)); ret = fthd_channel_ringbuf_send(dev_priv, dev_priv->channel_buf_h2t, ctx->dma_desc_obj->offset, 0x180, 0x30000000, &entry); if (ret) { pr_err("%s: fthd_channel_ringbuf_send: %d\n", __FUNCTION__, ret); return ret; } return fthd_channel_wait_ready(dev_priv, dev_priv->channel_buf_h2t, entry, 2000); }
int fthd_isp_cmd_set_loadfile(struct fthd_private *dev_priv) { struct isp_cmd_set_loadfile cmd; struct isp_mem_obj *file; const struct firmware *fw; const char *filename = NULL; const char *vendor, *board; int ret = 0; pr_debug("set loadfile\n"); vendor = dmi_get_system_info(DMI_BOARD_VENDOR); board = dmi_get_system_info(DMI_BOARD_NAME); memset(&cmd, 0, sizeof(cmd)); switch(dev_priv->sensor_id1) { case 0x164: filename = "facetimehd/8221_01XX.dat"; break; case 0x190: filename = "facetimehd/1222_01XX.dat"; break; case 0x8830: filename = "facetimehd/9112_01XX.dat"; break; case 0x9770: if (vendor && board && !strcmp(vendor, "Apple Inc.") && !strncmp(board, "MacBookAir", sizeof("MacBookAir")-1)) { filename = "facetimehd/1771_01XX.dat"; break; } switch(dev_priv->sensor_id0) { case 4: filename = "facetimehd/1874_01XX.dat"; break; default: filename = "facetimehd/1871_01XX.dat"; break; } break; case 0x9774: switch(dev_priv->sensor_id0) { case 4: filename = "facetimehd/1674_01XX.dat"; break; case 5: filename = "facetimehd/1675_01XX.dat"; break; default: filename = "facetimehd/1671_01XX.dat"; break; } break; default: break; } if (!filename) { pr_err("no set file for sensorid %04x %04x found\n", dev_priv->sensor_id0, dev_priv->sensor_id1); return -EINVAL; } /* The set file is allowed to be missing but we don't get calibration */ ret = request_firmware(&fw, filename, &dev_priv->pdev->dev); if (ret) return 0; /* Firmware memory is preallocated at init time */ BUG_ON(dev_priv->set_file); file = isp_mem_create(dev_priv, FTHD_MEM_SET_FILE, fw->size); FTHD_S2_MEMCPY_TOIO(file->offset, fw->data, fw->size); release_firmware(fw); dev_priv->set_file = file; pr_debug("set file: addr %08lx, size %d\n", file->offset, (int)file->size); cmd.addr = file->offset; cmd.length = file->size; return fthd_isp_cmd(dev_priv, CISP_CMD_CH_SET_FILE_LOAD, &cmd, sizeof(cmd), NULL); }
int fthd_isp_debug_cmd(struct fthd_private *dev_priv, enum fthd_isp_cmds command, void *buf, int request_len, int *response_len) { struct isp_mem_obj *request; struct isp_cmd_hdr cmd; u32 address, request_size, response_size; u32 entry; int len, ret; memset(&cmd, 0, sizeof(cmd)); if (response_len) { len = max(request_len, *response_len); } else { len = request_len; } len += sizeof(struct isp_cmd_hdr); pr_debug("sending debug cmd %d to firmware\n", command); request = isp_mem_create(dev_priv, FTHD_MEM_CMD, len); if (!request) { dev_err(&dev_priv->pdev->dev, "failed to allocate cmd memory object\n"); return -ENOMEM; } cmd.opcode = command; FTHD_S2_MEMCPY_TOIO(request->offset, &cmd, sizeof(struct isp_cmd_hdr)); if (request_len) FTHD_S2_MEMCPY_TOIO(request->offset + sizeof(struct isp_cmd_hdr), buf, request_len); ret = fthd_channel_ringbuf_send(dev_priv, dev_priv->channel_debug, request->offset, request_len + 8, (response_len ? *response_len : 0) + 8, &entry); if (ret) goto out; if (entry == (u32)-1) { ret = -EIO; goto out; } ret = fthd_channel_wait_ready(dev_priv, dev_priv->channel_debug, entry, 20000); if (ret) { if (response_len) *response_len = 0; goto out; } FTHD_S2_MEMCPY_FROMIO(&cmd, request->offset, sizeof(struct isp_cmd_hdr)); address = FTHD_S2_MEM_READ(entry + FTHD_RINGBUF_ADDRESS_FLAGS); request_size = FTHD_S2_MEM_READ(entry + FTHD_RINGBUF_REQUEST_SIZE); response_size = FTHD_S2_MEM_READ(entry + FTHD_RINGBUF_RESPONSE_SIZE); /* XXX: response size in the ringbuf is zero after command completion, how is buffer size verification done? */ if (response_len && *response_len) FTHD_S2_MEMCPY_FROMIO(buf, (address & ~3) + sizeof(struct isp_cmd_hdr), *response_len); pr_info("status %04x, request_len %d response len %d address_flags %x\n", cmd.status, request_size, response_size, address); ret = 0; out: isp_mem_destroy(request); return ret; }
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; }