diff --git a/bcwc_drv.h b/bcwc_drv.h index 4475249..4bdad4e 100644 --- a/bcwc_drv.h +++ b/bcwc_drv.h @@ -32,6 +32,14 @@ struct bcwc_reg { u32 value; }; +struct fw_channel { + char *name; + u32 offset; + u32 size; + u32 source; + u32 type; +}; + struct bcwc_private { struct pci_dev *pdev; unsigned int dma_mask; @@ -65,6 +73,10 @@ struct bcwc_private { struct isp_mem_obj *firmware; struct isp_mem_obj *ipc_queue; struct isp_mem_obj *heap; + + /* Firmware channels */ + int num_channels; + struct fw_channel **channels; }; #endif diff --git a/bcwc_hw.c b/bcwc_hw.c index 7468f2a..819bf56 100644 --- a/bcwc_hw.c +++ b/bcwc_hw.c @@ -670,7 +670,6 @@ static int bcwc_hw_irq_disable(struct bcwc_private *dev_priv) int bcwc_hw_init(struct bcwc_private *dev_priv) { - u32 val; int ret, i; ret = bcwc_hw_s2_init_pcie_link(dev_priv); diff --git a/bcwc_reg.h b/bcwc_reg.h index 1912dd9..2256a2e 100644 --- a/bcwc_reg.h +++ b/bcwc_reg.h @@ -160,6 +160,7 @@ #define ISP_REG_40004 0x40004 #define ISP_REG_40008 0x40008 #define ISP_REG_41000 0x41000 +#define ISP_REG_41020 0x41020 #define ISP_REG_41024 0x41024 #define ISP_IPC_CHAN_START 0x0128 diff --git a/isp.c b/isp.c index af1a29c..0546b16 100644 --- a/isp.c +++ b/isp.c @@ -175,14 +175,71 @@ static int isp_load_firmware(struct bcwc_private *dev_priv) return ret; } +static void isp_free_channel_info(struct bcwc_private *priv) +{ + struct fw_channel *chan; + int i; + for(i = 0; i < priv->num_channels; i++) { + chan = priv->channels[i]; + if (!chan) + continue; + + kfree(chan->name); + kfree(chan); + priv->channels[i] = NULL; + } + kfree(priv->channels); + priv->channels = NULL; +} + +static int isp_fill_channel_info(struct bcwc_private *priv, int offset, int num_channels) +{ + struct isp_channel_info *info; + struct fw_channel *chan; + int i; + + if (!num_channels) + return 0; + + priv->num_channels = num_channels; + priv->channels = kzalloc(num_channels * sizeof(struct fw_channel *), GFP_KERNEL); + if (!priv->channels) + goto out; + + for(i = 0; i < num_channels; i++) { + info = (struct isp_channel_info *)(priv->s2_mem + offset + i * 256); + + chan = kzalloc(sizeof(struct fw_channel), GFP_KERNEL); + if (!chan) + goto out; + + priv->channels[i] = chan; + + dev_info(&priv->pdev->dev, "Channel %d: %s, type %d, source %d, size %d, offset %x\n", + i, info->name, info->type, info->source, info->size, info->offset); + + chan->name = kstrdup(info->name, GFP_KERNEL); + if (!chan->name) + goto out; + + chan->type = info->type; + chan->source = info->source; + chan->size = info->size; + chan->offset = info->offset; + } + return 0; +out: + isp_free_channel_info(priv); + return -ENOMEM; +} + + int isp_init(struct bcwc_private *dev_priv) { struct isp_mem_obj *ipc_queue, *heap, *fw_args; - u32 num_channels, queue_size, heap_size; - u32 reg; - int i, retries, ret; - unsigned char *p; 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) @@ -330,6 +387,9 @@ int isp_init(struct bcwc_private *dev_priv) dev_info(&dev_priv->pdev->dev, "ISP second int after %dms\n", (retries - 1) * 10); + offset = BCWC_ISP_REG_READ(ISP_IPC_NUM_CHAN); + dev_info(&dev_priv->pdev->dev, "Channel description table at %08x\n", offset); + isp_fill_channel_info(dev_priv, offset, num_channels); } return 0; @@ -337,6 +397,7 @@ int isp_init(struct bcwc_private *dev_priv) int isp_uninit(struct bcwc_private *dev_priv) { + isp_free_channel_info(dev_priv); kfree(dev_priv->mem); return 0; } diff --git a/isp.h b/isp.h index aca15af..e7283e7 100644 --- a/isp.h +++ b/isp.h @@ -42,6 +42,15 @@ struct isp_fw_args { u32 fw_arg; u32 full_stats_mode; }; + +struct isp_channel_info { + char name[64]; /* really that big? */ + u32 type; + u32 source; + u32 size; + u32 offset; +}; + #define to_isp_mem_obj(x) container_of((x), struct isp_mem_obj, base) extern int isp_init(struct bcwc_private *dev_priv);