summaryrefslogtreecommitdiff
path: root/drivers/media
diff options
context:
space:
mode:
authorTom Cherry <tcherry@nvidia.com>2012-06-05 11:41:56 -0700
committerTom Cherry <tcherry@nvidia.com>2012-06-05 11:41:56 -0700
commitb46bcc0a3da47431f2711c3d63e9507cfab18ecd (patch)
tree6b9355395470108f5161840638bf48af0e10f3c1 /drivers/media
parent63fb092060747250a0dd305bd11018caebe23d65 (diff)
parentf61bdbde09605793cfa05f7c59545c62b5e08aa6 (diff)
Merge commit 'main-ics-2012.06.04-A5' into HEAD
Conflicts: drivers/media/video/tegra/nvavp/nvavp_dev.c Change-Id: I7779b0ce58004f80cccf6193148ac49551ce5da5
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/video/tegra/ad5816.c11
-rw-r--r--drivers/media/video/tegra/nvavp/Kconfig11
-rw-r--r--drivers/media/video/tegra/nvavp/nvavp_dev.c515
-rw-r--r--drivers/media/video/tegra/ov2710.c162
-rw-r--r--drivers/media/video/tegra/sh532u.c2
5 files changed, 513 insertions, 188 deletions
diff --git a/drivers/media/video/tegra/ad5816.c b/drivers/media/video/tegra/ad5816.c
index d95368f43cf6..ed113b3a187c 100644
--- a/drivers/media/video/tegra/ad5816.c
+++ b/drivers/media/video/tegra/ad5816.c
@@ -249,9 +249,8 @@ static int ad5816_i2c_wr16(struct ad5816_info *info, u8 reg, u16 val)
return 0;
}
-static int ad5816_gpio_wr(struct ad5816_info *info,
- enum ad5816_gpio_types i,
- int val) /* val: 0=deassert, 1=assert */
+static int ad5816_gpio_wr(struct ad5816_info *info, ad5816_gpio_types i,
+ int val) /* val: 0=deassert, 1=assert */
{
int err = -EINVAL;
if (info->gpio[i].valid) {
@@ -370,8 +369,7 @@ static void ad5816_gpio_init(struct ad5816_info *info)
}
}
-static int ad5816_vreg_dis(struct ad5816_info *info,
- enum ad5816_vreg i)
+static int ad5816_vreg_dis(struct ad5816_info *info, ad5816_vreg i)
{
int err = 0;
if (info->vreg[i].vreg_flag && (info->vreg[i].vreg != NULL)) {
@@ -396,8 +394,7 @@ static int ad5816_vreg_dis_all(struct ad5816_info *info)
return err;
}
-static int ad5816_vreg_en(struct ad5816_info *info,
- enum ad5816_vreg i)
+static int ad5816_vreg_en(struct ad5816_info *info, ad5816_vreg i)
{
int err = 0;
if (!info->vreg[i].vreg_flag && (info->vreg[i].vreg != NULL)) {
diff --git a/drivers/media/video/tegra/nvavp/Kconfig b/drivers/media/video/tegra/nvavp/Kconfig
index 2d3af3f79fb3..294253a0de49 100644
--- a/drivers/media/video/tegra/nvavp/Kconfig
+++ b/drivers/media/video/tegra/nvavp/Kconfig
@@ -8,3 +8,14 @@ config TEGRA_NVAVP
/dev/tegra_avpchannel.
If unsure, say N
+
+config TEGRA_NVAVP_AUDIO
+ bool "Enable Audio Channel support for Tegra NVAVP driver"
+ depends on TEGRA_NVAVP
+ default n
+ help
+ Enables support for the push-buffer mechanism based driver for the Tegra
+ audio multimedia framework. Exports the Tegra nvavp interface on device node
+ /dev/tegra_audio_avpchannel.
+
+ If unsure, say N
diff --git a/drivers/media/video/tegra/nvavp/nvavp_dev.c b/drivers/media/video/tegra/nvavp/nvavp_dev.c
index 012f50b7a5f4..b695aa16af59 100644
--- a/drivers/media/video/tegra/nvavp/nvavp_dev.c
+++ b/drivers/media/video/tegra/nvavp/nvavp_dev.c
@@ -72,6 +72,34 @@
/* AVP behavior params */
#define NVAVP_OS_IDLE_TIMEOUT 100 /* milli-seconds */
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+/* Two control channels: Audio and Video channels */
+#define NVAVP_NUM_CHANNELS 2
+
+#define NVAVP_AUDIO_CHANNEL 1
+
+#define IS_AUDIO_CHANNEL_ID(channel_id) (channel_id == NVAVP_AUDIO_CHANNEL ? 1: 0)
+#else
+#define NVAVP_NUM_CHANNELS 1
+#endif
+
+/* Channel ID 0 represents the Video channel control area */
+#define NVAVP_VIDEO_CHANNEL 0
+/* Channel ID 1 represents the Audio channel control area */
+
+#define IS_VIDEO_CHANNEL_ID(channel_id) (channel_id == NVAVP_VIDEO_CHANNEL ? 1: 0)
+
+
+struct nvavp_channel {
+ struct mutex pushbuffer_lock;
+ struct nvmap_handle_ref *pushbuf_handle;
+ unsigned long pushbuf_phys;
+ u8 *pushbuf_data;
+ u32 pushbuf_index;
+ u32 pushbuf_fence;
+ struct nv_e276_control *os_control;
+};
+
struct nvavp_info {
u32 clk_enabled;
struct clk *bsev_clk;
@@ -88,8 +116,10 @@ struct nvavp_info {
struct mutex open_lock;
int refcount;
- int initialized;
-
+ int video_initialized;
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ int audio_initialized;
+#endif
struct work_struct clock_disable_work;
/* os information */
@@ -101,22 +131,19 @@ struct nvavp_info {
/* client for driver allocations, persistent */
struct nvmap_client *nvmap;
- struct mutex pushbuffer_lock;
- struct nvmap_handle_ref *pushbuf_handle;
- unsigned long pushbuf_phys;
- u8 *pushbuf_data;
- u32 pushbuf_index;
- u32 pushbuf_fence;
bool pending;
- struct nv_e276_control *os_control;
+ struct nvavp_channel channel_info[NVAVP_NUM_CHANNELS];
struct nvhost_syncpt *nvhost_syncpt;
u32 syncpt_id;
u32 syncpt_value;
struct nvhost_device *nvhost_dev;
- struct miscdevice misc_dev;
+ struct miscdevice video_misc_dev;
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ struct miscdevice audio_misc_dev;
+#endif
atomic_t clock_stay_on_refcount;
};
@@ -128,8 +155,77 @@ struct nvavp_clientctx {
int num_relocs;
struct nvavp_info *nvavp;
int clock_stay_on;
+ int channel_id;
};
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+static int nvavp_get_audio_init_status(struct nvavp_info *nvavp)
+{
+ return nvavp->audio_initialized;
+}
+
+static void nvavp_set_audio_init_status(struct nvavp_info *nvavp, int status)
+{
+ nvavp->audio_initialized = status;
+}
+#endif
+
+static void nvavp_set_video_init_status(struct nvavp_info *nvavp, int status)
+{
+ nvavp->video_initialized = status;
+}
+
+static int nvavp_get_video_init_status(struct nvavp_info *nvavp)
+{
+ return nvavp->video_initialized;
+}
+
+static struct nvavp_channel *nvavp_get_channel_info(struct nvavp_info *nvavp, int channel_id)
+{
+ return &nvavp->channel_info[channel_id];
+}
+
+static void nvavp_set_channel_control_area(struct nvavp_info *nvavp, int channel_id)
+{
+ struct nv_e276_control *control;
+ struct nvavp_os_info *os = &nvavp->os_info;
+ u32 temp;
+ void *ptr;
+ struct nvavp_channel *channel_info;
+
+ ptr = os->data + os->control_offset + (sizeof(struct nv_e276_control) * channel_id);
+
+ channel_info = nvavp_get_channel_info(nvavp, channel_id);
+ channel_info->os_control = (struct nv_e276_control *)ptr;
+
+ control = channel_info->os_control;
+
+ /* init get and put pointers */
+ writel(0x0, &control->put);
+ writel(0x0, &control->get);
+
+ pr_debug("nvavp_set_channel_control_area for channel_id (%d):\
+ control->put (0x%x) control->get (0x%x)\n",
+ channel_id, &control->put, &control->get);
+
+ /* enable avp VDE clock control and disable iram clock gating */
+ writel(0x0, &control->idle_clk_enable);
+ writel(0x0, &control->iram_clk_gating);
+
+ /* enable avp idle timeout interrupt */
+ writel(0x1, &control->idle_notify_enable);
+ writel(NVAVP_OS_IDLE_TIMEOUT, &control->idle_notify_delay);
+
+ /* init dma start and end pointers */
+ writel(channel_info->pushbuf_phys, &control->dma_start);
+ writel((channel_info->pushbuf_phys + NVAVP_PUSHBUFFER_SIZE),
+ &control->dma_end);
+
+ writel(0x00, &channel_info->pushbuf_index);
+ temp = NVAVP_PUSHBUFFER_SIZE - NVAVP_PUSHBUFFER_MIN_UPDATE_SPACE;
+ writel(temp, &channel_info->pushbuf_fence);
+}
+
static struct clk *nvavp_clk_get(struct nvavp_info *nvavp, int id)
{
if (!nvavp)
@@ -175,7 +271,8 @@ static void nvavp_clks_disable(struct nvavp_info *nvavp)
static u32 nvavp_check_idle(struct nvavp_info *nvavp)
{
- struct nv_e276_control *control = nvavp->os_control;
+ struct nvavp_channel *channel_info = nvavp_get_channel_info(nvavp, NVAVP_VIDEO_CHANNEL);
+ struct nv_e276_control *control = channel_info->os_control;
return ((control->put == control->get)
&& (!atomic_read(&nvavp->clock_stay_on_refcount))) ? 1 : 0;
}
@@ -183,18 +280,20 @@ static u32 nvavp_check_idle(struct nvavp_info *nvavp)
static void clock_disable_handler(struct work_struct *work)
{
struct nvavp_info *nvavp;
+ struct nvavp_channel *channel_info;
nvavp = container_of(work, struct nvavp_info,
clock_disable_work);
+ channel_info = nvavp_get_channel_info(nvavp, NVAVP_VIDEO_CHANNEL);
- mutex_lock(&nvavp->pushbuffer_lock);
+ mutex_lock(&channel_info->pushbuffer_lock);
mutex_lock(&nvavp->open_lock);
if (nvavp_check_idle(nvavp) && nvavp->pending) {
nvavp->pending = false;
nvavp_clks_disable(nvavp);
}
mutex_unlock(&nvavp->open_lock);
- mutex_unlock(&nvavp->pushbuffer_lock);
+ mutex_unlock(&channel_info->pushbuffer_lock);
}
static int nvavp_service(struct nvavp_info *nvavp)
@@ -212,6 +311,10 @@ static int nvavp_service(struct nvavp_info *nvavp)
if (inbox & NVE276_OS_INTERRUPT_VIDEO_IDLE)
schedule_work(&nvavp->clock_disable_work);
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ if (inbox & NVE276_OS_INTERRUPT_AUDIO_IDLE)
+ pr_debug("nvavp_service NVE276_OS_INTERRUPT_AUDIO_IDLE\n");
+#endif
if (inbox & NVE276_OS_INTERRUPT_DEBUG_STRING) {
/* Should only occur with debug AVP OS builds */
debug_print = os->data;
@@ -337,99 +440,91 @@ static int nvavp_reset_vde(struct nvavp_info *nvavp)
return 0;
}
-static int nvavp_pushbuffer_alloc(struct nvavp_info *nvavp)
+static int nvavp_pushbuffer_alloc(struct nvavp_info *nvavp, int channel_id)
{
int ret = 0;
- nvavp->pushbuf_handle = nvmap_alloc(nvavp->nvmap, NVAVP_PUSHBUFFER_SIZE,
- SZ_1M, NVMAP_HANDLE_UNCACHEABLE, 0);
- if (IS_ERR(nvavp->pushbuf_handle)) {
+ struct nvavp_channel *channel_info = nvavp_get_channel_info(
+ nvavp, channel_id);
+
+ channel_info->pushbuf_handle = nvmap_alloc(nvavp->nvmap,
+ NVAVP_PUSHBUFFER_SIZE,
+ SZ_1M, NVMAP_HANDLE_UNCACHEABLE,
+ 0);
+ if (IS_ERR(channel_info->pushbuf_handle)) {
dev_err(&nvavp->nvhost_dev->dev,
"cannot create pushbuffer handle\n");
- ret = PTR_ERR(nvavp->pushbuf_handle);
+ ret = PTR_ERR(channel_info->pushbuf_handle);
goto err_pushbuf_alloc;
}
- nvavp->pushbuf_data = (u8 *)nvmap_mmap(nvavp->pushbuf_handle);
- if (!nvavp->pushbuf_data) {
+ channel_info->pushbuf_data = (u8 *)nvmap_mmap(
+ channel_info->pushbuf_handle);
+
+ if (!channel_info->pushbuf_data) {
dev_err(&nvavp->nvhost_dev->dev,
"cannot map pushbuffer handle\n");
ret = -ENOMEM;
goto err_pushbuf_mmap;
}
- nvavp->pushbuf_phys = nvmap_pin(nvavp->nvmap, nvavp->pushbuf_handle);
- if (IS_ERR((void *)nvavp->pushbuf_phys)) {
+ channel_info->pushbuf_phys = nvmap_pin(nvavp->nvmap,
+ channel_info->pushbuf_handle);
+ if (IS_ERR((void *)channel_info->pushbuf_phys)) {
dev_err(&nvavp->nvhost_dev->dev,
"cannot pin pushbuffer handle\n");
- ret = PTR_ERR((void *)nvavp->pushbuf_phys);
+ ret = PTR_ERR((void *)channel_info->pushbuf_phys);
goto err_pushbuf_pin;
}
- memset(nvavp->pushbuf_data, 0, NVAVP_PUSHBUFFER_SIZE);
+ memset(channel_info->pushbuf_data, 0, NVAVP_PUSHBUFFER_SIZE);
return 0;
err_pushbuf_pin:
- nvmap_munmap(nvavp->pushbuf_handle, nvavp->pushbuf_data);
+ nvmap_munmap(channel_info->pushbuf_handle, channel_info->pushbuf_data);
err_pushbuf_mmap:
- nvmap_free(nvavp->nvmap, nvavp->pushbuf_handle);
+ nvmap_free(nvavp->nvmap, channel_info->pushbuf_handle);
err_pushbuf_alloc:
return ret;
}
static void nvavp_pushbuffer_free(struct nvavp_info *nvavp)
{
- nvmap_unpin(nvavp->nvmap, nvavp->pushbuf_handle);
- nvmap_munmap(nvavp->pushbuf_handle, nvavp->pushbuf_data);
- nvmap_free(nvavp->nvmap, nvavp->pushbuf_handle);
+ int channel_id;
+
+ for (channel_id = 0; channel_id < NVAVP_NUM_CHANNELS; channel_id++) {
+ if (nvavp->channel_info[channel_id].pushbuf_data) {
+ nvmap_unpin(nvavp->nvmap,
+ nvavp->channel_info[channel_id].pushbuf_handle);
+ nvmap_munmap(
+ nvavp->channel_info[channel_id].pushbuf_handle,
+ nvavp->channel_info[channel_id].pushbuf_data);
+ nvmap_free(nvavp->nvmap,
+ nvavp->channel_info[channel_id].pushbuf_handle);
+ }
+ }
}
+
static int nvavp_pushbuffer_init(struct nvavp_info *nvavp)
{
- void *ptr;
- struct nvavp_os_info *os = &nvavp->os_info;
- struct nv_e276_control *control;
- u32 temp;
- int ret;
+ int ret, channel_id;
- ret = nvavp_pushbuffer_alloc(nvavp);
- if (ret) {
- dev_err(&nvavp->nvhost_dev->dev,
- "unable to alloc pushbuffer\n");
- return ret;
- }
-
- ptr = os->data;
- ptr += os->control_offset;
- nvavp->os_control = (struct nv_e276_control *)ptr;
-
- control = nvavp->os_control;
- memset(control, 0, sizeof(struct nvavp_os_info));
-
- /* init get and put pointers */
- writel(0x0, &control->put);
- writel(0x0, &control->get);
-
- /* enable avp VDE clock control and disable iram clock gating */
- writel(0x0, &control->idle_clk_enable);
- writel(0x0, &control->iram_clk_gating);
-
- /* enable avp idle timeout interrupt */
- writel(0x1, &control->idle_notify_enable);
- writel(NVAVP_OS_IDLE_TIMEOUT, &control->idle_notify_delay);
-
- /* init dma start and end pointers */
- writel(nvavp->pushbuf_phys, &control->dma_start);
- writel((nvavp->pushbuf_phys + NVAVP_PUSHBUFFER_SIZE),
- &control->dma_end);
-
- writel(0x00, &nvavp->pushbuf_index);
- temp = NVAVP_PUSHBUFFER_SIZE - NVAVP_PUSHBUFFER_MIN_UPDATE_SPACE;
- writel(temp, &nvavp->pushbuf_fence);
-
- nvavp->syncpt_id = NVSYNCPT_AVP_0;
- nvavp->syncpt_value = nvhost_syncpt_read(nvavp->nvhost_syncpt,
- nvavp->syncpt_id);
+ for (channel_id = 0; channel_id < NVAVP_NUM_CHANNELS; channel_id++) {
+ ret = nvavp_pushbuffer_alloc(nvavp, channel_id);
+ if (ret) {
+ dev_err(&nvavp->nvhost_dev->dev,
+ "unable to alloc pushbuffer\n");
+ return ret;
+ }
+ nvavp_set_channel_control_area(nvavp, channel_id);
+ if (IS_VIDEO_CHANNEL_ID(channel_id)) {
+ nvavp->syncpt_id = NVSYNCPT_AVP_0;
+ nvavp->syncpt_value = nvhost_syncpt_read(
+ nvavp->nvhost_syncpt,
+ nvavp->syncpt_id);
+ }
+ }
return 0;
}
@@ -440,37 +535,47 @@ static void nvavp_pushbuffer_deinit(struct nvavp_info *nvavp)
static int nvavp_pushbuffer_update(struct nvavp_info *nvavp, u32 phys_addr,
u32 gather_count, struct nvavp_syncpt *syncpt,
- u32 ext_ucode_flag)
+ u32 ext_ucode_flag, int channel_id)
{
- struct nv_e276_control *control = nvavp->os_control;
+ struct nvavp_channel *channel_info;
+ struct nv_e276_control *control;
u32 gather_cmd, setucode_cmd, sync = 0;
u32 wordcount = 0;
u32 index, value = -1;
- mutex_lock(&nvavp->pushbuffer_lock);
+ channel_info = nvavp_get_channel_info(nvavp, channel_id);
+
+ control = channel_info->os_control;
+ pr_debug("nvavp_pushbuffer_update for channel_id (%d):\
+ control->put (0x%x) control->get (0x%x)\n",
+ channel_id, &control->put, &control->get);
+
+ mutex_lock(&channel_info->pushbuffer_lock);
/* check for pushbuffer wrapping */
- if (nvavp->pushbuf_index >= nvavp->pushbuf_fence)
- nvavp->pushbuf_index = 0;
+ if (channel_info->pushbuf_index >= channel_info->pushbuf_fence)
+ channel_info->pushbuf_index = 0;
if (!ext_ucode_flag) {
setucode_cmd =
NVE26E_CH_OPCODE_INCR(NVE276_SET_MICROCODE_A, 3);
- index = wordcount + nvavp->pushbuf_index;
- writel(setucode_cmd, (nvavp->pushbuf_data + index));
+ index = wordcount + channel_info->pushbuf_index;
+ writel(setucode_cmd, (channel_info->pushbuf_data + index));
wordcount += sizeof(u32);
- index = wordcount + nvavp->pushbuf_index;
- writel(0, (nvavp->pushbuf_data + index));
+ index = wordcount + channel_info->pushbuf_index;
+ writel(0, (channel_info->pushbuf_data + index));
wordcount += sizeof(u32);
- index = wordcount + nvavp->pushbuf_index;
- writel(nvavp->ucode_info.phys, (nvavp->pushbuf_data + index));
+ index = wordcount + channel_info->pushbuf_index;
+ writel(nvavp->ucode_info.phys,
+ (channel_info->pushbuf_data + index));
wordcount += sizeof(u32);
- index = wordcount + nvavp->pushbuf_index;
- writel(nvavp->ucode_info.size, (nvavp->pushbuf_data + index));
+ index = wordcount + channel_info->pushbuf_index;
+ writel(nvavp->ucode_info.size,
+ (channel_info->pushbuf_data + index));
wordcount += sizeof(u32);
}
@@ -485,44 +590,58 @@ static int nvavp_pushbuffer_update(struct nvavp_info *nvavp, u32 phys_addr,
}
/* write commands out */
- index = wordcount + nvavp->pushbuf_index;
- writel(gather_cmd, (nvavp->pushbuf_data + index));
+ index = wordcount + channel_info->pushbuf_index;
+ writel(gather_cmd, (channel_info->pushbuf_data + index));
wordcount += sizeof(u32);
- index = wordcount + nvavp->pushbuf_index;
- writel(phys_addr, (nvavp->pushbuf_data + index));
+ index = wordcount + channel_info->pushbuf_index;
+ writel(phys_addr, (channel_info->pushbuf_data + index));
wordcount += sizeof(u32);
if (syncpt) {
- index = wordcount + nvavp->pushbuf_index;
- writel(sync, (nvavp->pushbuf_data + index));
+ index = wordcount + channel_info->pushbuf_index;
+ writel(sync, (channel_info->pushbuf_data + index));
wordcount += sizeof(u32);
}
/* enable clocks to VDE/BSEV */
- mutex_lock(&nvavp->open_lock);
- if (!nvavp->pending) {
- nvavp_clks_enable(nvavp);
- nvavp->pending = true;
+ if (IS_VIDEO_CHANNEL_ID(channel_id)) {
+ mutex_lock(&nvavp->open_lock);
+ if (!nvavp->pending) {
+ nvavp_clks_enable(nvavp);
+ nvavp->pending = true;
+ }
+ mutex_unlock(&nvavp->open_lock);
}
- mutex_unlock(&nvavp->open_lock);
/* update put pointer */
- nvavp->pushbuf_index = (nvavp->pushbuf_index + wordcount) &
+ channel_info->pushbuf_index = (channel_info->pushbuf_index + wordcount)&
(NVAVP_PUSHBUFFER_SIZE - 1);
- writel(nvavp->pushbuf_index, &control->put);
+
+ writel(channel_info->pushbuf_index, &control->put);
wmb();
/* wake up avp */
- writel(0xA0000001, NVAVP_OS_OUTBOX);
+ if (IS_VIDEO_CHANNEL_ID(channel_id)) {
+ pr_debug("Wake up Video Channel\n");
+ writel(0xA0000001, NVAVP_OS_OUTBOX);
+ }
+ else {
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ if (IS_AUDIO_CHANNEL_ID(channel_id)) {
+ pr_debug("Wake up Audio Channel\n");
+ writel(0xA0000002, NVAVP_OS_OUTBOX);
+ }
+#endif
+ }
/* Fill out fence struct */
if (syncpt) {
syncpt->id = nvavp->syncpt_id;
syncpt->value = value;
}
- mutex_unlock(&nvavp->pushbuffer_lock);
+ mutex_unlock(&channel_info->pushbuffer_lock);
return 0;
}
@@ -547,14 +666,14 @@ static int nvavp_load_ucode(struct nvavp_info *nvavp)
sprintf(fw_ucode_file, "nvavp_vid_ucode.bin");
ret = request_firmware(&nvavp_ucode_fw, fw_ucode_file,
- nvavp->misc_dev.this_device);
+ nvavp->video_misc_dev.this_device);
if (ret) {
/* Try alternative version */
sprintf(fw_ucode_file, "nvavp_vid_ucode_alt.bin");
ret = request_firmware(&nvavp_ucode_fw,
fw_ucode_file,
- nvavp->misc_dev.this_device);
+ nvavp->video_misc_dev.this_device);
if (ret) {
dev_err(&nvavp->nvhost_dev->dev,
@@ -652,7 +771,7 @@ static int nvavp_load_os(struct nvavp_info *nvavp, char *fw_os_file)
if (!os_info->os_bin) {
ret = request_firmware(&nvavp_os_fw, fw_os_file,
- nvavp->misc_dev.this_device);
+ nvavp->video_misc_dev.this_device);
if (ret) {
dev_err(&nvavp->nvhost_dev->dev,
"cannot read os firmware '%s'\n", fw_os_file);
@@ -717,14 +836,28 @@ err_req_fw:
return ret;
}
-static int nvavp_init(struct nvavp_info *nvavp)
+
+static int nvavp_os_init(struct nvavp_info *nvavp)
{
char fw_os_file[32];
int ret = 0;
+ int video_initialized, audio_initialized = 0;
- if (nvavp->initialized)
+ video_initialized = nvavp_get_video_init_status(nvavp);
+
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ audio_initialized = nvavp_get_audio_init_status(nvavp);
+#endif
+ pr_debug("video_initialized(%d) audio_initialized(%d)\n",
+ video_initialized, audio_initialized);
+
+ /* Video and Audio both are initialized */
+ if (video_initialized || audio_initialized)
return ret;
+ /* Video or Audio both are uninitialized */
+ pr_debug("video_initialized == audio_initialized (%d)\n",
+ nvavp->video_initialized);
#if defined(CONFIG_TEGRA_AVP_KERNEL_ON_MMU) /* Tegra2 with AVP MMU */
/* paddr is any address returned from nvmap_pin */
/* vaddr is AVP_KERNEL_VIRT_BASE */
@@ -768,7 +901,6 @@ static int nvavp_init(struct nvavp_info *nvavp)
nvavp->os_info.reset_addr = nvavp->os_info.phys;
nvavp->os_info.data = ioremap(nvavp->os_info.phys, SZ_1M);
#endif
-
ret = nvavp_load_os(nvavp, fw_os_file);
if (ret) {
dev_err(&nvavp->nvhost_dev->dev,
@@ -782,21 +914,45 @@ static int nvavp_init(struct nvavp_info *nvavp)
"unable to init pushbuffer\n");
goto err_exit;
}
+ tegra_init_legacy_irq_cop();
+ enable_irq(nvavp->mbox_from_avp_pend_irq);
+err_exit:
+ return ret;
+}
- ret = nvavp_load_ucode(nvavp);
+static int nvavp_init(struct nvavp_info *nvavp, int channel_id)
+{
+ int ret = 0;
+
+ ret = nvavp_os_init(nvavp);
if (ret) {
dev_err(&nvavp->nvhost_dev->dev,
- "unable to load ucode\n");
- goto err_exit;
+ "unable to load os firmware and allocate buffers\n");
}
- tegra_init_legacy_irq_cop();
+ if (IS_VIDEO_CHANNEL_ID(channel_id) &&
+ (!nvavp_get_video_init_status(nvavp)) ) {
+ pr_debug("nvavp_init : channel_ID (%d)\n", channel_id);
+ ret = nvavp_load_ucode(nvavp);
+ if (ret) {
+ dev_err(&nvavp->nvhost_dev->dev,
+ "unable to load ucode\n");
+ goto err_exit;
+ }
- nvavp_reset_vde(nvavp);
- nvavp_reset_avp(nvavp, nvavp->os_info.reset_addr);
- enable_irq(nvavp->mbox_from_avp_pend_irq);
+ nvavp_reset_vde(nvavp);
+ nvavp_reset_avp(nvavp, nvavp->os_info.reset_addr);
- nvavp->initialized = 1;
+ nvavp_set_video_init_status(nvavp, 1);
+ }
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ if (IS_AUDIO_CHANNEL_ID(channel_id) &&
+ (!nvavp_get_audio_init_status(nvavp))) {
+ pr_debug("nvavp_init : channel_ID (%d)\n", channel_id);
+ nvavp_reset_avp(nvavp, nvavp->os_info.reset_addr);
+ nvavp_set_audio_init_status(nvavp, 1);
+ }
+#endif
err_exit:
return ret;
@@ -804,22 +960,48 @@ err_exit:
static void nvavp_uninit(struct nvavp_info *nvavp)
{
- if (!nvavp->initialized)
+ int video_initialized, audio_initialized = 0;
+
+ video_initialized = nvavp_get_video_init_status(nvavp);
+
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ audio_initialized = nvavp_get_audio_init_status(nvavp);
+#endif
+
+ pr_debug("nvavp_uninit video_initialized(%d) audio_initialized(%d)\n",
+ video_initialized, audio_initialized);
+
+ /* Video and Audio both are uninitialized */
+ if (!video_initialized && !audio_initialized)
return;
- disable_irq(nvavp->mbox_from_avp_pend_irq);
+ if (video_initialized) {
+ pr_debug("nvavp_uninit nvavp->video_initialized\n");
+ cancel_work_sync(&nvavp->clock_disable_work);
- cancel_work_sync(&nvavp->clock_disable_work);
+ nvavp_halt_vde(nvavp);
- nvavp_pushbuffer_deinit(nvavp);
+ clk_disable(nvavp->sclk);
+ clk_disable(nvavp->emc_clk);
- nvavp_halt_vde(nvavp);
- nvavp_halt_avp(nvavp);
+ nvavp_set_video_init_status(nvavp, 0);
+ video_initialized = 0;
+ }
- clk_disable(nvavp->sclk);
- clk_disable(nvavp->emc_clk);
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ if (audio_initialized) {
+ nvavp_set_audio_init_status(nvavp, 0);
+ audio_initialized = 0;
+ }
+#endif
- nvavp->initialized = 0;
+ /* Video and Audio both becomes uninitialized */
+ if (video_initialized == audio_initialized) {
+ pr_debug("nvavp_uninit both channels unitialized\n");
+ disable_irq(nvavp->mbox_from_avp_pend_irq);
+ nvavp_pushbuffer_deinit(nvavp);
+ nvavp_halt_avp(nvavp);
+ }
}
static int nvavp_set_clock_ioctl(struct file *filp, unsigned int cmd,
@@ -1010,7 +1192,8 @@ static int nvavp_pushbuffer_submit_ioctl(struct file *filp, unsigned int cmd,
ret = nvavp_pushbuffer_update(nvavp,
(phys_addr + hdr.cmdbuf.offset),
hdr.cmdbuf.words, &syncpt,
- (hdr.flags & NVAVP_UCODE_EXT));
+ (hdr.flags & NVAVP_UCODE_EXT),
+ clientctx->channel_id);
if (copy_to_user((void __user *)user_hdr->syncpt, &syncpt,
sizeof(struct nvavp_syncpt))) {
@@ -1021,7 +1204,8 @@ static int nvavp_pushbuffer_submit_ioctl(struct file *filp, unsigned int cmd,
ret = nvavp_pushbuffer_update(nvavp,
(phys_addr + hdr.cmdbuf.offset),
hdr.cmdbuf.words, NULL,
- (hdr.flags & NVAVP_UCODE_EXT));
+ (hdr.flags & NVAVP_UCODE_EXT),
+ clientctx->channel_id);
}
err_reloc_info:
@@ -1075,7 +1259,7 @@ static int nvavp_force_clock_stay_on_ioctl(struct file *filp, unsigned int cmd,
return 0;
}
-static int tegra_nvavp_open(struct inode *inode, struct file *filp)
+static int tegra_nvavp_open(struct inode *inode, struct file *filp, int channel_id)
{
struct miscdevice *miscdev = filp->private_data;
struct nvavp_info *nvavp = dev_get_drvdata(miscdev->parent);
@@ -1092,8 +1276,11 @@ static int tegra_nvavp_open(struct inode *inode, struct file *filp)
mutex_lock(&nvavp->open_lock);
- if (!nvavp->refcount)
- ret = nvavp_init(nvavp);
+ pr_debug("tegra_nvavp_open channel_id (%d)\n", channel_id);
+
+ clientctx->channel_id = channel_id;
+
+ ret = nvavp_init(nvavp, channel_id);
if (!ret)
nvavp->refcount++;
@@ -1109,6 +1296,20 @@ static int tegra_nvavp_open(struct inode *inode, struct file *filp)
return ret;
}
+static int tegra_nvavp_video_open(struct inode *inode, struct file *filp)
+{
+ pr_debug("tegra_nvavp_video_open NVAVP_VIDEO_CHANNEL\n");
+ return tegra_nvavp_open(inode, filp, NVAVP_VIDEO_CHANNEL);
+}
+
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+static int tegra_nvavp_audio_open(struct inode *inode, struct file *filp)
+{
+ pr_debug("tegra_nvavp_audio_open NVAVP_AUDIO_CHANNEL\n");
+ return tegra_nvavp_open(inode, filp, NVAVP_AUDIO_CHANNEL);
+}
+#endif
+
static int tegra_nvavp_release(struct inode *inode, struct file *filp)
{
struct nvavp_clientctx *clientctx = filp->private_data;
@@ -1181,13 +1382,22 @@ static long tegra_nvavp_ioctl(struct file *filp, unsigned int cmd,
return ret;
}
-static const struct file_operations tegra_nvavp_fops = {
+static const struct file_operations tegra_video_nvavp_fops = {
.owner = THIS_MODULE,
- .open = tegra_nvavp_open,
+ .open = tegra_nvavp_video_open,
.release = tegra_nvavp_release,
.unlocked_ioctl = tegra_nvavp_ioctl,
};
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+static const struct file_operations tegra_audio_nvavp_fops = {
+ .owner = THIS_MODULE,
+ .open = tegra_nvavp_audio_open,
+ .release = tegra_nvavp_release,
+ .unlocked_ioctl = tegra_nvavp_ioctl,
+};
+#endif
+
static int tegra_nvavp_probe(struct nvhost_device *ndev,
struct nvhost_device_id *id_table)
{
@@ -1195,7 +1405,7 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev,
int irq;
unsigned int heap_mask;
u32 iovmm_addr;
- int ret = 0;
+ int ret = 0, channel_id;
irq = nvhost_get_irq_byname(ndev, "mbox_from_nvavp_pending");
if (irq < 0) {
@@ -1306,7 +1516,9 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev,
nvavp->mbox_from_avp_pend_irq = irq;
mutex_init(&nvavp->open_lock);
- mutex_init(&nvavp->pushbuffer_lock);
+
+ for (channel_id = 0; channel_id < NVAVP_NUM_CHANNELS; channel_id++)
+ mutex_init(&nvavp->channel_info[channel_id].pushbuffer_lock);
/* TODO DO NOT USE NVAVP DEVICE */
nvavp->cop_clk = clk_get(&ndev->dev, "cop");
@@ -1349,18 +1561,32 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev,
INIT_WORK(&nvavp->clock_disable_work, clock_disable_handler);
- nvavp->misc_dev.minor = MISC_DYNAMIC_MINOR;
- nvavp->misc_dev.name = "tegra_avpchannel";
- nvavp->misc_dev.fops = &tegra_nvavp_fops;
- nvavp->misc_dev.mode = S_IRWXUGO;
- nvavp->misc_dev.parent = &ndev->dev;
+ nvavp->video_misc_dev.minor = MISC_DYNAMIC_MINOR;
+ nvavp->video_misc_dev.name = "tegra_avpchannel";
+ nvavp->video_misc_dev.fops = &tegra_video_nvavp_fops;
+ nvavp->video_misc_dev.mode = S_IRWXUGO;
+ nvavp->video_misc_dev.parent = &ndev->dev;
- ret = misc_register(&nvavp->misc_dev);
+ ret = misc_register(&nvavp->video_misc_dev);
if (ret) {
dev_err(&ndev->dev, "unable to register misc device!\n");
goto err_misc_reg;
}
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ nvavp->audio_misc_dev.minor = MISC_DYNAMIC_MINOR;
+ nvavp->audio_misc_dev.name = "tegra_audio_avpchannel";
+ nvavp->audio_misc_dev.fops = &tegra_audio_nvavp_fops;
+ nvavp->audio_misc_dev.mode = S_IRWXUGO;
+ nvavp->audio_misc_dev.parent = &ndev->dev;
+
+ ret = misc_register(&nvavp->audio_misc_dev);
+ if (ret) {
+ dev_err(&ndev->dev, "unable to register misc device!\n");
+ goto err_audio_misc_reg;
+ }
+#endif
+
ret = request_irq(irq, nvavp_mbox_pending_isr, 0,
TEGRA_NVAVP_NAME, nvavp);
if (ret) {
@@ -1375,7 +1601,11 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev,
return 0;
err_req_irq_pend:
- misc_deregister(&nvavp->misc_dev);
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ misc_deregister(&nvavp->audio_misc_dev);
+err_audio_misc_reg:
+#endif
+ misc_deregister(&nvavp->video_misc_dev);
err_misc_reg:
clk_put(nvavp->emc_clk);
err_get_emc_clk:
@@ -1421,8 +1651,11 @@ static int tegra_nvavp_remove(struct nvhost_device *ndev)
nvavp_unload_ucode(nvavp);
nvavp_unload_os(nvavp);
- misc_deregister(&nvavp->misc_dev);
+ misc_deregister(&nvavp->video_misc_dev);
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ misc_deregister(&nvavp->audio_misc_dev);
+#endif
clk_put(nvavp->bsev_clk);
clk_put(nvavp->vde_clk);
clk_put(nvavp->cop_clk);
@@ -1463,7 +1696,7 @@ static int tegra_nvavp_resume(struct nvhost_device *ndev)
mutex_lock(&nvavp->open_lock);
if (nvavp->refcount)
- nvavp_init(nvavp);
+ nvavp_init(nvavp, NVAVP_VIDEO_CHANNEL);
mutex_unlock(&nvavp->open_lock);
diff --git a/drivers/media/video/tegra/ov2710.c b/drivers/media/video/tegra/ov2710.c
index 5e8eaa123124..293cb8932dfb 100644
--- a/drivers/media/video/tegra/ov2710.c
+++ b/drivers/media/video/tegra/ov2710.c
@@ -21,6 +21,8 @@
#include <linux/uaccess.h>
#include <media/ov2710.h>
+#define SIZEOF_I2C_TRANSBUF 32
+
struct ov2710_reg {
u16 addr;
u16 val;
@@ -30,6 +32,7 @@ struct ov2710_info {
int mode;
struct i2c_client *i2c_client;
struct ov2710_platform_data *pdata;
+ u8 i2c_trans_buf[SIZEOF_I2C_TRANSBUF];
};
#define OV2710_TABLE_WAIT_MS 0
@@ -152,7 +155,7 @@ static struct ov2710_reg mode_1920x1080[] = {
{0x3704, 0x44},
{0x3801, 0xd2},
- {0x3503, 0x17},
+ {0x3503, 0x33},
{0x3500, 0x00},
{0x3501, 0x00},
{0x3502, 0x00},
@@ -283,7 +286,7 @@ static struct ov2710_reg mode_1280x720[] = {
{0x3704, 0x40},
{0x3801, 0xbc},
- {0x3503, 0x17},
+ {0x3503, 0x33},
{0x3500, 0x00},
{0x3501, 0x00},
{0x3502, 0x00},
@@ -400,14 +403,39 @@ static int ov2710_write_reg(struct i2c_client *client, u16 addr, u8 val)
return err;
}
-static int ov2710_write_table(struct i2c_client *client,
+static int ov2710_write_bulk_reg(struct i2c_client *client, u8 *data, int len)
+{
+ int err;
+ struct i2c_msg msg;
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = len;
+ msg.buf = data;
+
+ err = i2c_transfer(client->adapter, &msg, 1);
+ if (err == 1)
+ return 0;
+
+ pr_err("ov2710: i2c bulk transfer failed at %x\n",
+ (int)data[0] << 8 | data[1]);
+
+ return err;
+}
+
+static int ov2710_write_table(struct ov2710_info *info,
const struct ov2710_reg table[],
const struct ov2710_reg override_list[],
int num_override_regs)
{
int err;
- const struct ov2710_reg *next;
- int i;
+ const struct ov2710_reg *next, *n_next;
+ u8 *b_ptr = info->i2c_trans_buf;
+ unsigned int buf_filled = 0;
+ unsigned int i;
u16 val;
for (next = table; next->addr != OV2710_TABLE_END; next++) {
@@ -416,9 +444,7 @@ static int ov2710_write_table(struct i2c_client *client,
continue;
}
-
val = next->val;
-
/* When an override list is passed in, replace the reg */
/* value to write if the reg is in the list */
if (override_list) {
@@ -430,9 +456,28 @@ static int ov2710_write_table(struct i2c_client *client,
}
}
- err = ov2710_write_reg(client, next->addr, val);
+ if (!buf_filled) {
+ b_ptr = info->i2c_trans_buf;
+ *b_ptr++ = next->addr >> 8;
+ *b_ptr++ = next->addr & 0xff;
+ buf_filled = 2;
+ }
+ *b_ptr++ = val;
+ buf_filled++;
+
+ n_next = next + 1;
+ if (n_next->addr != OV2710_TABLE_END &&
+ n_next->addr != OV2710_TABLE_WAIT_MS &&
+ buf_filled < SIZEOF_I2C_TRANSBUF &&
+ n_next->addr == next->addr + 1) {
+ continue;
+ }
+
+ err = ov2710_write_bulk_reg(info->i2c_client,
+ info->i2c_trans_buf, buf_filled);
if (err)
return err;
+ buf_filled = 0;
}
return 0;
}
@@ -463,7 +508,7 @@ static int ov2710_set_mode(struct ov2710_info *info, struct ov2710_mode *mode)
ov2710_get_coarse_time_regs(reg_list + 2, mode->coarse_time);
ov2710_get_gain_reg(reg_list + 5, mode->gain);
- err = ov2710_write_table(info->i2c_client, mode_table[sensor_mode],
+ err = ov2710_write_table(info, mode_table[sensor_mode],
reg_list, 6);
if (err)
return err;
@@ -474,51 +519,37 @@ static int ov2710_set_mode(struct ov2710_info *info, struct ov2710_mode *mode)
static int ov2710_set_frame_length(struct ov2710_info *info, u32 frame_length)
{
- struct ov2710_reg reg_list[2];
- int i = 0;
int ret;
+ struct ov2710_reg reg_list[2];
+ u8 *b_ptr = info->i2c_trans_buf;
ov2710_get_frame_length_regs(reg_list, frame_length);
- for (i = 0; i < 2; i++) {
- ret = ov2710_write_reg(info->i2c_client, reg_list[i].addr,
- reg_list[i].val);
- if (ret)
- return ret;
- }
+ *b_ptr++ = reg_list[0].addr >> 8;
+ *b_ptr++ = reg_list[0].addr & 0xff;
+ *b_ptr++ = reg_list[0].val & 0xff;
+ *b_ptr++ = reg_list[1].val & 0xff;
+ ret = ov2710_write_bulk_reg(info->i2c_client, info->i2c_trans_buf, 4);
- return 0;
+ return ret;
}
static int ov2710_set_coarse_time(struct ov2710_info *info, u32 coarse_time)
{
int ret;
-
struct ov2710_reg reg_list[3];
- int i = 0;
+ u8 *b_ptr = info->i2c_trans_buf;
ov2710_get_coarse_time_regs(reg_list, coarse_time);
- ret = ov2710_write_reg(info->i2c_client, 0x3212, 0x01);
- if (ret)
- return ret;
-
- for (i = 0; i < 3; i++) {
- ret = ov2710_write_reg(info->i2c_client, reg_list[i].addr,
- reg_list[i].val);
- if (ret)
- return ret;
- }
-
- ret = ov2710_write_reg(info->i2c_client, 0x3212, 0x11);
- if (ret)
- return ret;
+ *b_ptr++ = reg_list[0].addr >> 8;
+ *b_ptr++ = reg_list[0].addr & 0xff;
+ *b_ptr++ = reg_list[0].val & 0xff;
+ *b_ptr++ = reg_list[1].val & 0xff;
+ *b_ptr++ = reg_list[2].val & 0xff;
+ ret = ov2710_write_bulk_reg(info->i2c_client, info->i2c_trans_buf, 5);
- ret = ov2710_write_reg(info->i2c_client, 0x3212, 0xa1);
- if (ret)
- return ret;
-
- return 0;
+ return ret;
}
static int ov2710_set_gain(struct ov2710_info *info, u16 gain)
@@ -533,6 +564,48 @@ static int ov2710_set_gain(struct ov2710_info *info, u16 gain)
return ret;
}
+static int ov2710_set_group_hold(struct ov2710_info *info, struct ov2710_ae *ae)
+{
+ int ret;
+ int count = 0;
+ bool groupHoldEnabled = false;
+
+ if (ae->gain_enable)
+ count++;
+ if (ae->coarse_time_enable)
+ count++;
+ if (ae->frame_length_enable)
+ count++;
+ if (count >= 2)
+ groupHoldEnabled = true;
+
+ if (groupHoldEnabled) {
+ ret = ov2710_write_reg(info->i2c_client, 0x3212, 0x01);
+ if (ret)
+ return ret;
+ }
+
+ if (ae->gain_enable)
+ ov2710_set_gain(info, ae->gain);
+ if (ae->coarse_time_enable)
+ ov2710_set_coarse_time(info, ae->coarse_time);
+ if (ae->frame_length_enable)
+ ov2710_set_frame_length(info, ae->frame_length);
+
+ if (groupHoldEnabled) {
+ ret = ov2710_write_reg(info->i2c_client, 0x3212, 0x11);
+ if (ret)
+ return ret;
+
+ ret = ov2710_write_reg(info->i2c_client, 0x3212, 0xa1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+
static int ov2710_get_status(struct ov2710_info *info, u8 *status)
{
int err;
@@ -567,6 +640,17 @@ static long ov2710_ioctl(struct file *file,
return ov2710_set_coarse_time(info, (u32)arg);
case OV2710_IOCTL_SET_GAIN:
return ov2710_set_gain(info, (u16)arg);
+ case OV2710_IOCTL_SET_GROUP_HOLD:
+ {
+ struct ov2710_ae ae;
+ if (copy_from_user(&ae,
+ (const void __user *)arg,
+ sizeof(struct ov2710_ae))) {
+ pr_info("%s %d\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ return ov2710_set_group_hold(info, &ae);
+ }
case OV2710_IOCTL_GET_STATUS:
{
u8 status;
diff --git a/drivers/media/video/tegra/sh532u.c b/drivers/media/video/tegra/sh532u.c
index f41b44ce9530..4c7ef5aeaeab 100644
--- a/drivers/media/video/tegra/sh532u.c
+++ b/drivers/media/video/tegra/sh532u.c
@@ -532,7 +532,7 @@ static int sh532u_vreg_init(struct sh532u_info *info)
else
dev_info(&info->i2c_client->dev,
"%s no regulator found for %s. "
- "This board may not have an"
+ "This board may not have an "
"independent %s regulator.\n",
__func__, info->vreg[j].vreg_name,
info->vreg[j].vreg_name);