diff options
author | Tom Cherry <tcherry@nvidia.com> | 2012-06-05 11:41:56 -0700 |
---|---|---|
committer | Tom Cherry <tcherry@nvidia.com> | 2012-06-05 11:41:56 -0700 |
commit | b46bcc0a3da47431f2711c3d63e9507cfab18ecd (patch) | |
tree | 6b9355395470108f5161840638bf48af0e10f3c1 /drivers/media | |
parent | 63fb092060747250a0dd305bd11018caebe23d65 (diff) | |
parent | f61bdbde09605793cfa05f7c59545c62b5e08aa6 (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.c | 11 | ||||
-rw-r--r-- | drivers/media/video/tegra/nvavp/Kconfig | 11 | ||||
-rw-r--r-- | drivers/media/video/tegra/nvavp/nvavp_dev.c | 515 | ||||
-rw-r--r-- | drivers/media/video/tegra/ov2710.c | 162 | ||||
-rw-r--r-- | drivers/media/video/tegra/sh532u.c | 2 |
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); |