pdata = container_of(inode->i_cdev,
struct nvhost_device_data, cdev);
ch = nvhost_channel_map(pdata);
- if (!ch) {
+ if (!ch || !ch->dev) {
pr_err("%s: failed to map channel\n", __func__);
return -ENOMEM;
}
struct nvhost_master *nvhost_master = nvhost_get_host(dev);
struct nvhost_device_data *pdata = platform_get_drvdata(dev);
+ pdata->channels = kzalloc(pdata->num_channels *
+ sizeof(struct nvhost_channel *),
+ GFP_KERNEL);
+
/* Create debugfs directory for the device */
nvhost_device_debug_init(dev);
int nvhost_client_device_release(struct platform_device *dev)
{
struct nvhost_device_data *pdata = platform_get_drvdata(dev);
- struct nvhost_channel *ch = pdata->channel;
/* Release nvhost module resources */
nvhost_module_deinit(dev);
/* Remove debugFS */
nvhost_device_debug_deinit(dev);
- /* Unmap nvhost channel */
- if (ch)
- nvhost_putchannel(ch);
+ /* Release all nvhost channel of dev*/
+ nvhost_channel_release(pdata);
return 0;
}
struct output *o = data;
struct nvhost_master *m;
struct nvhost_device_data *pdata;
+ int index;
if (pdev == NULL)
return 0;
m = nvhost_get_host(pdev);
pdata = platform_get_drvdata(pdev);
- ch = pdata->channel;
- if (!ch) {
- nvhost_debug_output(o, "channel already un-mapped for %s\n",
- pdev->name);
- return 0;
- }
- nvhost_getchannel(ch);
- if (ch->chid != locked_id)
- mutex_lock(&ch->cdma.lock);
- if (fifo)
- nvhost_get_chip_ops()->debug.show_channel_fifo(
+ for (index = 0; index < pdata->num_channels; index++) {
+ ch = pdata->channels[index];
+ if (!ch || !ch->dev) {
+ nvhost_debug_output(o, "%d channel of %s unmapped\n",
+ index + 1, pdev->name);
+ continue;
+ }
+ nvhost_getchannel(ch);
+ if (ch->chid != locked_id)
+ mutex_lock(&ch->cdma.lock);
+ if (fifo)
+ nvhost_get_chip_ops()->debug.show_channel_fifo(
+ m, ch, o, ch->chid);
+ nvhost_get_chip_ops()->debug.show_channel_cdma(
m, ch, o, ch->chid);
- nvhost_get_chip_ops()->debug.show_channel_cdma(
- m, ch, o, ch->chid);
- if (ch->chid != locked_id)
- mutex_unlock(&ch->cdma.lock);
+ if (ch->chid != locked_id)
+ mutex_unlock(&ch->cdma.lock);
+ nvhost_putchannel(ch);
+ }
- nvhost_putchannel(ch);
return 0;
}
for (index = 0; index < pdata->num_clks; index++)
clk_disable_unprepare(pdata->clk[index]);
- if (pdata->channel)
- nvhost_channel_suspend(pdata->channel);
+ for (index = 0; index < pdata->num_channels; index++)
+ if (pdata->channels[index])
+ nvhost_channel_suspend(pdata->channels[index]);
/* disable parent's clock if required */
if (dev->parent && dev->parent != &platform_bus)
return NULL;
}
+/* return any one of assigned channel from device
+ * This API can be used to check if any channel assigned to device
+ */
+struct nvhost_channel *nvhost_check_channel(struct nvhost_device_data *pdata)
+{
+ int i;
+ struct nvhost_channel *ch = NULL;
+
+ for (i = 0; i < pdata->num_channels; i++) {
+ ch = pdata->channels[i];
+ if (ch && ch->dev)
+ return ch;
+ }
+
+ return ch;
+}
+
+/* Check if more than channel needed for device and assign */
+int nvhost_channel_assign(struct nvhost_device_data *pdata,
+ struct nvhost_channel *ch)
+{
+ int i;
+
+ for (i = 0; i < pdata->num_channels; i++) {
+ if (!pdata->channels[i]) {
+ pdata->channels[i] = ch;
+ pdata->num_mapped_chs++;
+ ch->dev_chid = i;
+ return 0;
+ }
+ }
+ dev_err(&pdata->pdev->dev, "%s: All channels assigned\n", __func__);
+
+ return -EINVAL;
+}
+
+/* Releases all channels assigned with device */
+int nvhost_channel_release(struct nvhost_device_data *pdata)
+{
+ struct nvhost_channel *ch;
+ int i;
+
+ for (i = 0; i < pdata->num_channels; i++) {
+ ch = pdata->channels[i];
+ if (ch && ch->dev)
+ nvhost_putchannel(ch);
+ }
+ return 0;
+}
/* Unmap channel from device and free all resources, deinit device */
int nvhost_channel_unmap(struct nvhost_channel *ch)
{
ch->ctxhandler = NULL;
ch->cur_ctx = NULL;
ch->aperture = NULL;
- pdata->channel = NULL;
+ pdata->channels[ch->dev_chid] = NULL;
+ pdata->num_mapped_chs--;
mutex_unlock(&host->chlist_mutex);
mutex_lock(&host->chlist_mutex);
max_channels = host->info.nb_channels;
- /* Check if already channel assigned for device */
- if (pdata->channel) {
- ch = pdata->channel;
- nvhost_getchannel(ch);
+ /* Check if already channel(s) assigned for device */
+ if (pdata->num_channels == pdata->num_mapped_chs) {
+ ch = nvhost_check_channel(pdata);
+ if (ch)
+ nvhost_getchannel(ch);
mutex_unlock(&host->chlist_mutex);
return ch;
}
if (ch->chid == NVHOST_INVALID_CHANNEL) {
ch->dev = pdata->pdev;
ch->chid = index;
- pdata->channel = ch;
+ nvhost_channel_assign(pdata, ch);
nvhost_set_chanops(ch);
} else {
dev_err(&host->dev->dev, "%s: wrong channel map\n", __func__);
struct nvhost_master *dev)
{
int err;
- struct nvhost_device_data *pdata = platform_get_drvdata(ch->dev);
/* Link platform_device to nvhost_channel */
err = channel_op(ch).init(ch, dev);
ch->chid);
return err;
}
- pdata->channel = ch;
return nvhost_cdma_init(&ch->cdma);
}
struct nvhost_channel_ops ops;
atomic_t refcount;
int chid;
+ int dev_chid;
u32 syncpt_id;
struct mutex reflock;
struct mutex submitlock;
int nvhost_alloc_channels(struct nvhost_master *host);
struct nvhost_channel *nvhost_channel_map(struct nvhost_device_data *pdata);
int nvhost_channel_unmap(struct nvhost_channel *ch);
+int nvhost_channel_release(struct nvhost_device_data *pdata);
int nvhost_channel_list_free(struct nvhost_master *host);
+struct nvhost_channel *nvhost_check_channel(struct nvhost_device_data *pdata);
int nvhost_channel_init(struct nvhost_channel *ch,
struct nvhost_master *dev);
static struct platform_device tegra_isp01b_device;
struct nvhost_device_data t124_isp_info = {
+ .num_channels = 1,
/* FIXME: control clocks from user space instead of hard-coding here */
.moduleid = NVHOST_MODULE_ISP,
.modulemutexes = {NVMODMUTEX_ISP_0},
struct nvhost_device_data t124_ispb_info = {
+ .num_channels = 1,
/* FIXME: control clocks from user space instead of hard-coding here */
.moduleid = (1 << 16) | NVHOST_MODULE_ISP,
.modulemutexes = {NVMODMUTEX_ISP_1},
static struct platform_device tegra_vi01b_device;
struct nvhost_device_data t124_vi_info = {
+ .num_channels = 1,
/* FIXME: resolve powergating dependency with DIS */
/* FIXME: control clocks from user space instead of hard-coding here */
.moduleid = NVHOST_MODULE_VI,
};
struct nvhost_device_data t124_vib_info = {
+ .num_channels = 1,
/* FIXME: resolve powergating dependency with DIS */
/* FIXME: control clocks from user space instead of hard-coding here */
.moduleid = (1 << 16 | NVHOST_MODULE_VI),
};
struct nvhost_device_data t124_msenc_info = {
+ .num_channels = 1,
.version = NVHOST_ENCODE_MSENC_VER(3, 1),
.class = NV_VIDEO_ENCODE_MSENC_CLASS_ID,
.clocks = {{"msenc", UINT_MAX, 0, TEGRA_MC_CLIENT_MSENC},
};
struct nvhost_device_data t124_tsec_info = {
+ .num_channels = 1,
.version = NVHOST_ENCODE_TSEC_VER(1, 0),
.class = NV_TSEC_CLASS_ID,
.exclusive = true,
};
struct nvhost_device_data t124_vic_info = {
+ .num_channels = 1,
.modulemutexes = {NVMODMUTEX_VIC},
.clocks = {{"vic03", UINT_MAX, 0, TEGRA_MC_CLIENT_VIC},
{"emc", UINT_MAX} },
*/
struct nvhost_device_data t132_isp_info = {
+ .num_channels = 1,
/* FIXME: control clocks from user space instead of hard-coding here */
.moduleid = NVHOST_MODULE_ISP,
.modulemutexes = {NVMODMUTEX_ISP_0},
};
struct nvhost_device_data t132_ispb_info = {
+ .num_channels = 1,
/* FIXME: control clocks from user space instead of hard-coding here */
.moduleid = (1 << 16) | NVHOST_MODULE_ISP,
.modulemutexes = {NVMODMUTEX_ISP_1},
};
struct nvhost_device_data t132_vi_info = {
+ .num_channels = 1,
/* FIXME: resolve powergating dependency with DIS */
/* FIXME: control clocks from user space instead of hard-coding here */
.moduleid = NVHOST_MODULE_VI,
};
struct nvhost_device_data t132_vib_info = {
+ .num_channels = 1,
/* FIXME: resolve powergating dependency with DIS */
/* FIXME: control clocks from user space instead of hard-coding here */
.moduleid = (1 << 16 | NVHOST_MODULE_VI),
};
struct nvhost_device_data t132_msenc_info = {
+ .num_channels = 1,
.version = NVHOST_ENCODE_MSENC_VER(3, 1),
.class = NV_VIDEO_ENCODE_MSENC_CLASS_ID,
.clocks = {{"msenc", UINT_MAX, 0, TEGRA_MC_CLIENT_MSENC},
};
struct nvhost_device_data t132_tsec_info = {
+ .num_channels = 1,
.version = NVHOST_ENCODE_TSEC_VER(1, 0),
.class = NV_TSEC_CLASS_ID,
.exclusive = true,
#ifdef CONFIG_ARCH_TEGRA_VIC
struct nvhost_device_data t132_vic_info = {
+ .num_channels = 1,
.modulemutexes = {NVMODMUTEX_VIC},
.clocks = {{"vic03", UINT_MAX, 0, TEGRA_MC_CLIENT_VIC},
{"emc", UINT_MAX} },
{
struct nvhost_device_data *pdata = nvhost_get_devdata(dev);
struct vic03 *v;
- struct nvhost_channel *ch = pdata->channel;
+ struct nvhost_channel *ch = pdata->channels[0];
if (ch && ch->dev) {
mutex_lock(&ch->submitlock);
struct mutex lock; /* Power management lock */
struct list_head client_list; /* List of clients and rate requests */
- struct nvhost_channel *channel; /* Channel assigned for the module */
+ int num_channels; /* Max num of channel supported */
+ int num_mapped_chs; /* Num of channel mapped to device */
+
+ /* Channel(s) assigned for the module */
+ struct nvhost_channel **channels;
/* device node for channel operations */
dev_t cdev_region;