diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-14 12:13:30 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-15 16:36:22 -0300 |
commit | b285192a43f0432d82c2c10974204e78af0da596 (patch) | |
tree | 618aa87e760c9c949eca9e4df6ae0eeffa11dcfc /drivers/media/video/cx18/cx18-mailbox.c | |
parent | 68de959f773a1d49096835c411390bceff5d1549 (diff) | |
download | lwn-b285192a43f0432d82c2c10974204e78af0da596.tar.gz lwn-b285192a43f0432d82c2c10974204e78af0da596.zip |
[media] rename most media/video pci drivers to media/pci
Rename all PCI drivers with their own directory under
drivers/media/video into drivers/media/pci and update the
building system.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/cx18/cx18-mailbox.c')
-rw-r--r-- | drivers/media/video/cx18/cx18-mailbox.c | 870 |
1 files changed, 0 insertions, 870 deletions
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c deleted file mode 100644 index eabf00c6351b..000000000000 --- a/drivers/media/video/cx18/cx18-mailbox.c +++ /dev/null @@ -1,870 +0,0 @@ -/* - * cx18 mailbox functions - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#include <stdarg.h> - -#include "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-scb.h" -#include "cx18-irq.h" -#include "cx18-mailbox.h" -#include "cx18-queue.h" -#include "cx18-streams.h" -#include "cx18-alsa-pcm.h" /* FIXME make configurable */ - -static const char *rpu_str[] = { "APU", "CPU", "EPU", "HPU" }; - -#define API_FAST (1 << 2) /* Short timeout */ -#define API_SLOW (1 << 3) /* Additional 300ms timeout */ - -struct cx18_api_info { - u32 cmd; - u8 flags; /* Flags, see above */ - u8 rpu; /* Processing unit */ - const char *name; /* The name of the command */ -}; - -#define API_ENTRY(rpu, x, f) { (x), (f), (rpu), #x } - -static const struct cx18_api_info api_info[] = { - /* MPEG encoder API */ - API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0), - API_ENTRY(CPU, CX18_EPU_DEBUG, 0), - API_ENTRY(CPU, CX18_CREATE_TASK, 0), - API_ENTRY(CPU, CX18_DESTROY_TASK, 0), - API_ENTRY(CPU, CX18_CPU_CAPTURE_START, API_SLOW), - API_ENTRY(CPU, CX18_CPU_CAPTURE_STOP, API_SLOW), - API_ENTRY(CPU, CX18_CPU_CAPTURE_PAUSE, 0), - API_ENTRY(CPU, CX18_CPU_CAPTURE_RESUME, 0), - API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0), - API_ENTRY(CPU, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 0), - API_ENTRY(CPU, CX18_CPU_SET_VIDEO_IN, 0), - API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RATE, 0), - API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RESOLUTION, 0), - API_ENTRY(CPU, CX18_CPU_SET_FILTER_PARAM, 0), - API_ENTRY(CPU, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 0), - API_ENTRY(CPU, CX18_CPU_SET_MEDIAN_CORING, 0), - API_ENTRY(CPU, CX18_CPU_SET_INDEXTABLE, 0), - API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PARAMETERS, 0), - API_ENTRY(CPU, CX18_CPU_SET_VIDEO_MUTE, 0), - API_ENTRY(CPU, CX18_CPU_SET_AUDIO_MUTE, 0), - API_ENTRY(CPU, CX18_CPU_SET_MISC_PARAMETERS, 0), - API_ENTRY(CPU, CX18_CPU_SET_RAW_VBI_PARAM, API_SLOW), - API_ENTRY(CPU, CX18_CPU_SET_CAPTURE_LINE_NO, 0), - API_ENTRY(CPU, CX18_CPU_SET_COPYRIGHT, 0), - API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PID, 0), - API_ENTRY(CPU, CX18_CPU_SET_VIDEO_PID, 0), - API_ENTRY(CPU, CX18_CPU_SET_VER_CROP_LINE, 0), - API_ENTRY(CPU, CX18_CPU_SET_GOP_STRUCTURE, 0), - API_ENTRY(CPU, CX18_CPU_SET_SCENE_CHANGE_DETECTION, 0), - API_ENTRY(CPU, CX18_CPU_SET_ASPECT_RATIO, 0), - API_ENTRY(CPU, CX18_CPU_SET_SKIP_INPUT_FRAME, 0), - API_ENTRY(CPU, CX18_CPU_SET_SLICED_VBI_PARAM, 0), - API_ENTRY(CPU, CX18_CPU_SET_USERDATA_PLACE_HOLDER, 0), - API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0), - API_ENTRY(CPU, CX18_CPU_SET_VFC_PARAM, 0), - API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0), - API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST), - API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, API_SLOW), - API_ENTRY(APU, CX18_APU_START, 0), - API_ENTRY(APU, CX18_APU_STOP, 0), - API_ENTRY(APU, CX18_APU_RESETAI, 0), - API_ENTRY(CPU, CX18_CPU_DEBUG_PEEK32, 0), - API_ENTRY(0, 0, 0), -}; - -static const struct cx18_api_info *find_api_info(u32 cmd) -{ - int i; - - for (i = 0; api_info[i].cmd; i++) - if (api_info[i].cmd == cmd) - return &api_info[i]; - return NULL; -} - -/* Call with buf of n*11+1 bytes */ -static char *u32arr2hex(u32 data[], int n, char *buf) -{ - char *p; - int i; - - for (i = 0, p = buf; i < n; i++, p += 11) { - /* kernel snprintf() appends '\0' always */ - snprintf(p, 12, " %#010x", data[i]); - } - *p = '\0'; - return buf; -} - -static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name) -{ - char argstr[MAX_MB_ARGUMENTS*11+1]; - - if (!(cx18_debug & CX18_DBGFLG_API)) - return; - - CX18_DEBUG_API("%s: req %#010x ack %#010x cmd %#010x err %#010x args%s" - "\n", name, mb->request, mb->ack, mb->cmd, mb->error, - u32arr2hex(mb->args, MAX_MB_ARGUMENTS, argstr)); -} - - -/* - * Functions that run in a work_queue work handling context - */ - -static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl) -{ - struct cx18_buffer *buf; - - if (s->dvb == NULL || !s->dvb->enabled || mdl->bytesused == 0) - return; - - /* We ignore mdl and buf readpos accounting here - it doesn't matter */ - - /* The likely case */ - if (list_is_singular(&mdl->buf_list)) { - buf = list_first_entry(&mdl->buf_list, struct cx18_buffer, - list); - if (buf->bytesused) - dvb_dmx_swfilter(&s->dvb->demux, - buf->buf, buf->bytesused); - return; - } - - list_for_each_entry(buf, &mdl->buf_list, list) { - if (buf->bytesused == 0) - break; - dvb_dmx_swfilter(&s->dvb->demux, buf->buf, buf->bytesused); - } -} - -static void cx18_mdl_send_to_videobuf(struct cx18_stream *s, - struct cx18_mdl *mdl) -{ - struct cx18_videobuf_buffer *vb_buf; - struct cx18_buffer *buf; - u8 *p; - u32 offset = 0; - int dispatch = 0; - - if (mdl->bytesused == 0) - return; - - /* Acquire a videobuf buffer, clone to and and release it */ - spin_lock(&s->vb_lock); - if (list_empty(&s->vb_capture)) - goto out; - - vb_buf = list_first_entry(&s->vb_capture, struct cx18_videobuf_buffer, - vb.queue); - - p = videobuf_to_vmalloc(&vb_buf->vb); - if (!p) - goto out; - - offset = vb_buf->bytes_used; - list_for_each_entry(buf, &mdl->buf_list, list) { - if (buf->bytesused == 0) - break; - - if ((offset + buf->bytesused) <= vb_buf->vb.bsize) { - memcpy(p + offset, buf->buf, buf->bytesused); - offset += buf->bytesused; - vb_buf->bytes_used += buf->bytesused; - } - } - - /* If we've filled the buffer as per the callers res then dispatch it */ - if (vb_buf->bytes_used >= s->vb_bytes_per_frame) { - dispatch = 1; - vb_buf->bytes_used = 0; - } - - if (dispatch) { - vb_buf->vb.ts = ktime_to_timeval(ktime_get()); - list_del(&vb_buf->vb.queue); - vb_buf->vb.state = VIDEOBUF_DONE; - wake_up(&vb_buf->vb.done); - } - - mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies); - -out: - spin_unlock(&s->vb_lock); -} - -static void cx18_mdl_send_to_alsa(struct cx18 *cx, struct cx18_stream *s, - struct cx18_mdl *mdl) -{ - struct cx18_buffer *buf; - - if (mdl->bytesused == 0) - return; - - /* We ignore mdl and buf readpos accounting here - it doesn't matter */ - - /* The likely case */ - if (list_is_singular(&mdl->buf_list)) { - buf = list_first_entry(&mdl->buf_list, struct cx18_buffer, - list); - if (buf->bytesused) - cx->pcm_announce_callback(cx->alsa, buf->buf, - buf->bytesused); - return; - } - - list_for_each_entry(buf, &mdl->buf_list, list) { - if (buf->bytesused == 0) - break; - cx->pcm_announce_callback(cx->alsa, buf->buf, buf->bytesused); - } -} - -static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order) -{ - u32 handle, mdl_ack_count, id; - struct cx18_mailbox *mb; - struct cx18_mdl_ack *mdl_ack; - struct cx18_stream *s; - struct cx18_mdl *mdl; - int i; - - mb = &order->mb; - handle = mb->args[0]; - s = cx18_handle_to_stream(cx, handle); - - if (s == NULL) { - CX18_WARN("Got DMA done notification for unknown/inactive" - " handle %d, %s mailbox seq no %d\n", handle, - (order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) ? - "stale" : "good", mb->request); - return; - } - - mdl_ack_count = mb->args[2]; - mdl_ack = order->mdl_ack; - for (i = 0; i < mdl_ack_count; i++, mdl_ack++) { - id = mdl_ack->id; - /* - * Simple integrity check for processing a stale (and possibly - * inconsistent mailbox): make sure the MDL id is in the - * valid range for the stream. - * - * We go through the trouble of dealing with stale mailboxes - * because most of the time, the mailbox data is still valid and - * unchanged (and in practice the firmware ping-pongs the - * two mdl_ack buffers so mdl_acks are not stale). - * - * There are occasions when we get a half changed mailbox, - * which this check catches for a handle & id mismatch. If the - * handle and id do correspond, the worst case is that we - * completely lost the old MDL, but pick up the new MDL - * early (but the new mdl_ack is guaranteed to be good in this - * case as the firmware wouldn't point us to a new mdl_ack until - * it's filled in). - * - * cx18_queue_get_mdl() will detect the lost MDLs - * and send them back to q_free for fw rotation eventually. - */ - if ((order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) && - !(id >= s->mdl_base_idx && - id < (s->mdl_base_idx + s->buffers))) { - CX18_WARN("Fell behind! Ignoring stale mailbox with " - " inconsistent data. Lost MDL for mailbox " - "seq no %d\n", mb->request); - break; - } - mdl = cx18_queue_get_mdl(s, id, mdl_ack->data_used); - - CX18_DEBUG_HI_DMA("DMA DONE for %s (MDL %d)\n", s->name, id); - if (mdl == NULL) { - CX18_WARN("Could not find MDL %d for stream %s\n", - id, s->name); - continue; - } - - CX18_DEBUG_HI_DMA("%s recv bytesused = %d\n", - s->name, mdl->bytesused); - - if (s->type == CX18_ENC_STREAM_TYPE_TS) { - cx18_mdl_send_to_dvb(s, mdl); - cx18_enqueue(s, mdl, &s->q_free); - } else if (s->type == CX18_ENC_STREAM_TYPE_PCM) { - /* Pass the data to cx18-alsa */ - if (cx->pcm_announce_callback != NULL) { - cx18_mdl_send_to_alsa(cx, s, mdl); - cx18_enqueue(s, mdl, &s->q_free); - } else { - cx18_enqueue(s, mdl, &s->q_full); - } - } else if (s->type == CX18_ENC_STREAM_TYPE_YUV) { - cx18_mdl_send_to_videobuf(s, mdl); - cx18_enqueue(s, mdl, &s->q_free); - } else { - cx18_enqueue(s, mdl, &s->q_full); - if (s->type == CX18_ENC_STREAM_TYPE_IDX) - cx18_stream_rotate_idx_mdls(cx); - } - } - /* Put as many MDLs as possible back into fw use */ - cx18_stream_load_fw_queue(s); - - wake_up(&cx->dma_waitq); - if (s->id != -1) - wake_up(&s->waitq); -} - -static void epu_debug(struct cx18 *cx, struct cx18_in_work_order *order) -{ - char *p; - char *str = order->str; - - CX18_DEBUG_INFO("%x %s\n", order->mb.args[0], str); - p = strchr(str, '.'); - if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str) - CX18_INFO("FW version: %s\n", p - 1); -} - -static void epu_cmd(struct cx18 *cx, struct cx18_in_work_order *order) -{ - switch (order->rpu) { - case CPU: - { - switch (order->mb.cmd) { - case CX18_EPU_DMA_DONE: - epu_dma_done(cx, order); - break; - case CX18_EPU_DEBUG: - epu_debug(cx, order); - break; - default: - CX18_WARN("Unknown CPU to EPU mailbox command %#0x\n", - order->mb.cmd); - break; - } - break; - } - case APU: - CX18_WARN("Unknown APU to EPU mailbox command %#0x\n", - order->mb.cmd); - break; - default: - break; - } -} - -static -void free_in_work_order(struct cx18 *cx, struct cx18_in_work_order *order) -{ - atomic_set(&order->pending, 0); -} - -void cx18_in_work_handler(struct work_struct *work) -{ - struct cx18_in_work_order *order = - container_of(work, struct cx18_in_work_order, work); - struct cx18 *cx = order->cx; - epu_cmd(cx, order); - free_in_work_order(cx, order); -} - - -/* - * Functions that run in an interrupt handling context - */ - -static void mb_ack_irq(struct cx18 *cx, struct cx18_in_work_order *order) -{ - struct cx18_mailbox __iomem *ack_mb; - u32 ack_irq, req; - - switch (order->rpu) { - case APU: - ack_irq = IRQ_EPU_TO_APU_ACK; - ack_mb = &cx->scb->apu2epu_mb; - break; - case CPU: - ack_irq = IRQ_EPU_TO_CPU_ACK; - ack_mb = &cx->scb->cpu2epu_mb; - break; - default: - CX18_WARN("Unhandled RPU (%d) for command %x ack\n", - order->rpu, order->mb.cmd); - return; - } - - req = order->mb.request; - /* Don't ack if the RPU has gotten impatient and timed us out */ - if (req != cx18_readl(cx, &ack_mb->request) || - req == cx18_readl(cx, &ack_mb->ack)) { - CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our " - "incoming %s to EPU mailbox (sequence no. %u) " - "while processing\n", - rpu_str[order->rpu], rpu_str[order->rpu], req); - order->flags |= CX18_F_EWO_MB_STALE_WHILE_PROC; - return; - } - cx18_writel(cx, req, &ack_mb->ack); - cx18_write_reg_expect(cx, ack_irq, SW2_INT_SET, ack_irq, ack_irq); - return; -} - -static int epu_dma_done_irq(struct cx18 *cx, struct cx18_in_work_order *order) -{ - u32 handle, mdl_ack_offset, mdl_ack_count; - struct cx18_mailbox *mb; - int i; - - mb = &order->mb; - handle = mb->args[0]; - mdl_ack_offset = mb->args[1]; - mdl_ack_count = mb->args[2]; - - if (handle == CX18_INVALID_TASK_HANDLE || - mdl_ack_count == 0 || mdl_ack_count > CX18_MAX_MDL_ACKS) { - if ((order->flags & CX18_F_EWO_MB_STALE) == 0) - mb_ack_irq(cx, order); - return -1; - } - - for (i = 0; i < sizeof(struct cx18_mdl_ack) * mdl_ack_count; i += sizeof(u32)) - ((u32 *)order->mdl_ack)[i / sizeof(u32)] = - cx18_readl(cx, cx->enc_mem + mdl_ack_offset + i); - - if ((order->flags & CX18_F_EWO_MB_STALE) == 0) - mb_ack_irq(cx, order); - return 1; -} - -static -int epu_debug_irq(struct cx18 *cx, struct cx18_in_work_order *order) -{ - u32 str_offset; - char *str = order->str; - - str[0] = '\0'; - str_offset = order->mb.args[1]; - if (str_offset) { - cx18_setup_page(cx, str_offset); - cx18_memcpy_fromio(cx, str, cx->enc_mem + str_offset, 252); - str[252] = '\0'; - cx18_setup_page(cx, SCB_OFFSET); - } - - if ((order->flags & CX18_F_EWO_MB_STALE) == 0) - mb_ack_irq(cx, order); - - return str_offset ? 1 : 0; -} - -static inline -int epu_cmd_irq(struct cx18 *cx, struct cx18_in_work_order *order) -{ - int ret = -1; - - switch (order->rpu) { - case CPU: - { - switch (order->mb.cmd) { - case CX18_EPU_DMA_DONE: - ret = epu_dma_done_irq(cx, order); - break; - case CX18_EPU_DEBUG: - ret = epu_debug_irq(cx, order); - break; - default: - CX18_WARN("Unknown CPU to EPU mailbox command %#0x\n", - order->mb.cmd); - break; - } - break; - } - case APU: - CX18_WARN("Unknown APU to EPU mailbox command %#0x\n", - order->mb.cmd); - break; - default: - break; - } - return ret; -} - -static inline -struct cx18_in_work_order *alloc_in_work_order_irq(struct cx18 *cx) -{ - int i; - struct cx18_in_work_order *order = NULL; - - for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) { - /* - * We only need "pending" atomic to inspect its contents, - * and need not do a check and set because: - * 1. Any work handler thread only clears "pending" and only - * on one, particular work order at a time, per handler thread. - * 2. "pending" is only set here, and we're serialized because - * we're called in an IRQ handler context. - */ - if (atomic_read(&cx->in_work_order[i].pending) == 0) { - order = &cx->in_work_order[i]; - atomic_set(&order->pending, 1); - break; - } - } - return order; -} - -void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu) -{ - struct cx18_mailbox __iomem *mb; - struct cx18_mailbox *order_mb; - struct cx18_in_work_order *order; - int submit; - int i; - - switch (rpu) { - case CPU: - mb = &cx->scb->cpu2epu_mb; - break; - case APU: - mb = &cx->scb->apu2epu_mb; - break; - default: - return; - } - - order = alloc_in_work_order_irq(cx); - if (order == NULL) { - CX18_WARN("Unable to find blank work order form to schedule " - "incoming mailbox command processing\n"); - return; - } - - order->flags = 0; - order->rpu = rpu; - order_mb = &order->mb; - - /* mb->cmd and mb->args[0] through mb->args[2] */ - for (i = 0; i < 4; i++) - (&order_mb->cmd)[i] = cx18_readl(cx, &mb->cmd + i); - - /* mb->request and mb->ack. N.B. we want to read mb->ack last */ - for (i = 0; i < 2; i++) - (&order_mb->request)[i] = cx18_readl(cx, &mb->request + i); - - if (order_mb->request == order_mb->ack) { - CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our " - "incoming %s to EPU mailbox (sequence no. %u)" - "\n", - rpu_str[rpu], rpu_str[rpu], order_mb->request); - if (cx18_debug & CX18_DBGFLG_WARN) - dump_mb(cx, order_mb, "incoming"); - order->flags = CX18_F_EWO_MB_STALE_UPON_RECEIPT; - } - - /* - * Individual EPU command processing is responsible for ack-ing - * a non-stale mailbox as soon as possible - */ - submit = epu_cmd_irq(cx, order); - if (submit > 0) { - queue_work(cx->in_work_queue, &order->work); - } -} - - -/* - * Functions called from a non-interrupt, non work_queue context - */ - -static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) -{ - const struct cx18_api_info *info = find_api_info(cmd); - u32 irq, req, ack, err; - struct cx18_mailbox __iomem *mb; - wait_queue_head_t *waitq; - struct mutex *mb_lock; - unsigned long int t0, timeout, ret; - int i; - char argstr[MAX_MB_ARGUMENTS*11+1]; - DEFINE_WAIT(w); - - if (info == NULL) { - CX18_WARN("unknown cmd %x\n", cmd); - return -EINVAL; - } - - if (cx18_debug & CX18_DBGFLG_API) { /* only call u32arr2hex if needed */ - if (cmd == CX18_CPU_DE_SET_MDL) { - if (cx18_debug & CX18_DBGFLG_HIGHVOL) - CX18_DEBUG_HI_API("%s\tcmd %#010x args%s\n", - info->name, cmd, - u32arr2hex(data, args, argstr)); - } else - CX18_DEBUG_API("%s\tcmd %#010x args%s\n", - info->name, cmd, - u32arr2hex(data, args, argstr)); - } - - switch (info->rpu) { - case APU: - waitq = &cx->mb_apu_waitq; - mb_lock = &cx->epu2apu_mb_lock; - irq = IRQ_EPU_TO_APU; - mb = &cx->scb->epu2apu_mb; - break; - case CPU: - waitq = &cx->mb_cpu_waitq; - mb_lock = &cx->epu2cpu_mb_lock; - irq = IRQ_EPU_TO_CPU; - mb = &cx->scb->epu2cpu_mb; - break; - default: - CX18_WARN("Unknown RPU (%d) for API call\n", info->rpu); - return -EINVAL; - } - - mutex_lock(mb_lock); - /* - * Wait for an in-use mailbox to complete - * - * If the XPU is responding with Ack's, the mailbox shouldn't be in - * a busy state, since we serialize access to it on our end. - * - * If the wait for ack after sending a previous command was interrupted - * by a signal, we may get here and find a busy mailbox. After waiting, - * mark it "not busy" from our end, if the XPU hasn't ack'ed it still. - */ - req = cx18_readl(cx, &mb->request); - timeout = msecs_to_jiffies(10); - ret = wait_event_timeout(*waitq, - (ack = cx18_readl(cx, &mb->ack)) == req, - timeout); - if (req != ack) { - /* waited long enough, make the mbox "not busy" from our end */ - cx18_writel(cx, req, &mb->ack); - CX18_ERR("mbox was found stuck busy when setting up for %s; " - "clearing busy and trying to proceed\n", info->name); - } else if (ret != timeout) - CX18_DEBUG_API("waited %u msecs for busy mbox to be acked\n", - jiffies_to_msecs(timeout-ret)); - - /* Build the outgoing mailbox */ - req = ((req & 0xfffffffe) == 0xfffffffe) ? 1 : req + 1; - - cx18_writel(cx, cmd, &mb->cmd); - for (i = 0; i < args; i++) - cx18_writel(cx, data[i], &mb->args[i]); - cx18_writel(cx, 0, &mb->error); - cx18_writel(cx, req, &mb->request); - cx18_writel(cx, req - 1, &mb->ack); /* ensure ack & req are distinct */ - - /* - * Notify the XPU and wait for it to send an Ack back - */ - timeout = msecs_to_jiffies((info->flags & API_FAST) ? 10 : 20); - - CX18_DEBUG_HI_IRQ("sending interrupt SW1: %x to send %s\n", - irq, info->name); - - /* So we don't miss the wakeup, prepare to wait before notifying fw */ - prepare_to_wait(waitq, &w, TASK_UNINTERRUPTIBLE); - cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq); - - t0 = jiffies; - ack = cx18_readl(cx, &mb->ack); - if (ack != req) { - schedule_timeout(timeout); - ret = jiffies - t0; - ack = cx18_readl(cx, &mb->ack); - } else { - ret = jiffies - t0; - } - - finish_wait(waitq, &w); - - if (req != ack) { - mutex_unlock(mb_lock); - if (ret >= timeout) { - /* Timed out */ - CX18_DEBUG_WARN("sending %s timed out waiting %d msecs " - "for RPU acknowledgement\n", - info->name, jiffies_to_msecs(ret)); - } else { - CX18_DEBUG_WARN("woken up before mailbox ack was ready " - "after submitting %s to RPU. only " - "waited %d msecs on req %u but awakened" - " with unmatched ack %u\n", - info->name, - jiffies_to_msecs(ret), - req, ack); - } - return -EINVAL; - } - - if (ret >= timeout) - CX18_DEBUG_WARN("failed to be awakened upon RPU acknowledgment " - "sending %s; timed out waiting %d msecs\n", - info->name, jiffies_to_msecs(ret)); - else - CX18_DEBUG_HI_API("waited %u msecs for %s to be acked\n", - jiffies_to_msecs(ret), info->name); - - /* Collect data returned by the XPU */ - for (i = 0; i < MAX_MB_ARGUMENTS; i++) - data[i] = cx18_readl(cx, &mb->args[i]); - err = cx18_readl(cx, &mb->error); - mutex_unlock(mb_lock); - - /* - * Wait for XPU to perform extra actions for the caller in some cases. - * e.g. CX18_CPU_DE_RELEASE_MDL will cause the CPU to send all MDLs - * back in a burst shortly thereafter - */ - if (info->flags & API_SLOW) - cx18_msleep_timeout(300, 0); - - if (err) - CX18_DEBUG_API("mailbox error %08x for command %s\n", err, - info->name); - return err ? -EIO : 0; -} - -int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]) -{ - return cx18_api_call(cx, cmd, args, data); -} - -static int cx18_set_filter_param(struct cx18_stream *s) -{ - struct cx18 *cx = s->cx; - u32 mode; - int ret; - - mode = (cx->filter_mode & 1) ? 2 : (cx->spatial_strength ? 1 : 0); - ret = cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4, - s->handle, 1, mode, cx->spatial_strength); - mode = (cx->filter_mode & 2) ? 2 : (cx->temporal_strength ? 1 : 0); - ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4, - s->handle, 0, mode, cx->temporal_strength); - ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4, - s->handle, 2, cx->filter_mode >> 2, 0); - return ret; -} - -int cx18_api_func(void *priv, u32 cmd, int in, int out, - u32 data[CX2341X_MBOX_MAX_DATA]) -{ - struct cx18_stream *s = priv; - struct cx18 *cx = s->cx; - - switch (cmd) { - case CX2341X_ENC_SET_OUTPUT_PORT: - return 0; - case CX2341X_ENC_SET_FRAME_RATE: - return cx18_vapi(cx, CX18_CPU_SET_VIDEO_IN, 6, - s->handle, 0, 0, 0, 0, data[0]); - case CX2341X_ENC_SET_FRAME_SIZE: - return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RESOLUTION, 3, - s->handle, data[1], data[0]); - case CX2341X_ENC_SET_STREAM_TYPE: - return cx18_vapi(cx, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 2, - s->handle, data[0]); - case CX2341X_ENC_SET_ASPECT_RATIO: - return cx18_vapi(cx, CX18_CPU_SET_ASPECT_RATIO, 2, - s->handle, data[0]); - - case CX2341X_ENC_SET_GOP_PROPERTIES: - return cx18_vapi(cx, CX18_CPU_SET_GOP_STRUCTURE, 3, - s->handle, data[0], data[1]); - case CX2341X_ENC_SET_GOP_CLOSURE: - return 0; - case CX2341X_ENC_SET_AUDIO_PROPERTIES: - return cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2, - s->handle, data[0]); - case CX2341X_ENC_MUTE_AUDIO: - return cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, - s->handle, data[0]); - case CX2341X_ENC_SET_BIT_RATE: - return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RATE, 5, - s->handle, data[0], data[1], data[2], data[3]); - case CX2341X_ENC_MUTE_VIDEO: - return cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, - s->handle, data[0]); - case CX2341X_ENC_SET_FRAME_DROP_RATE: - return cx18_vapi(cx, CX18_CPU_SET_SKIP_INPUT_FRAME, 2, - s->handle, data[0]); - case CX2341X_ENC_MISC: - return cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 4, - s->handle, data[0], data[1], data[2]); - case CX2341X_ENC_SET_DNR_FILTER_MODE: - cx->filter_mode = (data[0] & 3) | (data[1] << 2); - return cx18_set_filter_param(s); - case CX2341X_ENC_SET_DNR_FILTER_PROPS: - cx->spatial_strength = data[0]; - cx->temporal_strength = data[1]; - return cx18_set_filter_param(s); - case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE: - return cx18_vapi(cx, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 3, - s->handle, data[0], data[1]); - case CX2341X_ENC_SET_CORING_LEVELS: - return cx18_vapi(cx, CX18_CPU_SET_MEDIAN_CORING, 5, - s->handle, data[0], data[1], data[2], data[3]); - } - CX18_WARN("Unknown cmd %x\n", cmd); - return 0; -} - -int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], - u32 cmd, int args, ...) -{ - va_list ap; - int i; - - va_start(ap, args); - for (i = 0; i < args; i++) - data[i] = va_arg(ap, u32); - va_end(ap); - return cx18_api(cx, cmd, args, data); -} - -int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...) -{ - u32 data[MAX_MB_ARGUMENTS]; - va_list ap; - int i; - - if (cx == NULL) { - CX18_ERR("cx == NULL (cmd=%x)\n", cmd); - return 0; - } - if (args > MAX_MB_ARGUMENTS) { - CX18_ERR("args too big (cmd=%x)\n", cmd); - args = MAX_MB_ARGUMENTS; - } - va_start(ap, args); - for (i = 0; i < args; i++) - data[i] = va_arg(ap, u32); - va_end(ap); - return cx18_api(cx, cmd, args, data); -} |