cx18-irq.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /*
  2. * cx18 interrupt handling
  3. *
  4. * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  19. * 02111-1307 USA
  20. */
  21. #include "cx18-driver.h"
  22. #include "cx18-io.h"
  23. #include "cx18-firmware.h"
  24. #include "cx18-fileops.h"
  25. #include "cx18-queue.h"
  26. #include "cx18-irq.h"
  27. #include "cx18-ioctl.h"
  28. #include "cx18-mailbox.h"
  29. #include "cx18-vbi.h"
  30. #include "cx18-scb.h"
  31. #define DMA_MAGIC_COOKIE 0x000001fe
  32. static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb)
  33. {
  34. u32 handle = mb->args[0];
  35. struct cx18_stream *s = NULL;
  36. struct cx18_buffer *buf;
  37. u32 off;
  38. int i;
  39. int id;
  40. for (i = 0; i < CX18_MAX_STREAMS; i++) {
  41. s = &cx->streams[i];
  42. if ((handle == s->handle) && (s->dvb.enabled))
  43. break;
  44. if (s->v4l2dev && handle == s->handle)
  45. break;
  46. }
  47. if (i == CX18_MAX_STREAMS) {
  48. CX18_WARN("DMA done for unknown handle %d for stream %s\n",
  49. handle, s->name);
  50. mb->error = CXERR_NOT_OPEN;
  51. mb->cmd = 0;
  52. cx18_mb_ack(cx, mb);
  53. return;
  54. }
  55. off = mb->args[1];
  56. if (mb->args[2] != 1)
  57. CX18_WARN("Ack struct = %d for %s\n",
  58. mb->args[2], s->name);
  59. id = cx18_read_enc(cx, off);
  60. buf = cx18_queue_get_buf_irq(s, id, cx18_read_enc(cx, off + 4));
  61. CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id);
  62. if (buf) {
  63. cx18_buf_sync_for_cpu(s, buf);
  64. if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) {
  65. /* process the buffer here */
  66. CX18_DEBUG_HI_DMA("TS recv and sent bytesused=%d\n",
  67. buf->bytesused);
  68. dvb_dmx_swfilter(&s->dvb.demux, buf->buf,
  69. buf->bytesused);
  70. cx18_buf_sync_for_device(s, buf);
  71. cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
  72. (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
  73. 1, buf->id, s->buf_size);
  74. } else
  75. set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
  76. } else {
  77. CX18_WARN("Could not find buf %d for stream %s\n",
  78. cx18_read_enc(cx, off), s->name);
  79. }
  80. mb->error = 0;
  81. mb->cmd = 0;
  82. cx18_mb_ack(cx, mb);
  83. wake_up(&cx->dma_waitq);
  84. if (s->id != -1)
  85. wake_up(&s->waitq);
  86. }
  87. static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb)
  88. {
  89. char str[256] = { 0 };
  90. char *p;
  91. if (mb->args[1]) {
  92. cx18_setup_page(cx, mb->args[1]);
  93. cx18_memcpy_fromio(cx, str, cx->enc_mem + mb->args[1], 252);
  94. str[252] = 0;
  95. }
  96. cx18_mb_ack(cx, mb);
  97. CX18_DEBUG_INFO("%x %s\n", mb->args[0], str);
  98. p = strchr(str, '.');
  99. if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str)
  100. CX18_INFO("FW version: %s\n", p - 1);
  101. }
  102. static void hpu_cmd(struct cx18 *cx, u32 sw1)
  103. {
  104. struct cx18_mailbox mb;
  105. if (sw1 & IRQ_CPU_TO_EPU) {
  106. cx18_memcpy_fromio(cx, &mb, &cx->scb->cpu2epu_mb, sizeof(mb));
  107. mb.error = 0;
  108. switch (mb.cmd) {
  109. case CX18_EPU_DMA_DONE:
  110. epu_dma_done(cx, &mb);
  111. break;
  112. case CX18_EPU_DEBUG:
  113. epu_debug(cx, &mb);
  114. break;
  115. default:
  116. CX18_WARN("Unexpected mailbox command %08x\n", mb.cmd);
  117. break;
  118. }
  119. }
  120. if (sw1 & (IRQ_APU_TO_EPU | IRQ_HPU_TO_EPU))
  121. CX18_WARN("Unexpected interrupt %08x\n", sw1);
  122. }
  123. irqreturn_t cx18_irq_handler(int irq, void *dev_id)
  124. {
  125. struct cx18 *cx = (struct cx18 *)dev_id;
  126. u32 sw1, sw1_mask;
  127. u32 sw2, sw2_mask;
  128. u32 hw2, hw2_mask;
  129. spin_lock(&cx->dma_reg_lock);
  130. hw2_mask = cx18_read_reg(cx, HW2_INT_MASK5_PCI);
  131. hw2 = cx18_read_reg(cx, HW2_INT_CLR_STATUS) & hw2_mask;
  132. sw2_mask = cx18_read_reg(cx, SW2_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU_ACK;
  133. sw2 = cx18_read_reg(cx, SW2_INT_STATUS) & sw2_mask;
  134. sw1_mask = cx18_read_reg(cx, SW1_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU;
  135. sw1 = cx18_read_reg(cx, SW1_INT_STATUS) & sw1_mask;
  136. cx18_write_reg(cx, sw2&sw2_mask, SW2_INT_STATUS);
  137. cx18_write_reg(cx, sw1&sw1_mask, SW1_INT_STATUS);
  138. cx18_write_reg(cx, hw2&hw2_mask, HW2_INT_CLR_STATUS);
  139. if (sw1 || sw2 || hw2)
  140. CX18_DEBUG_HI_IRQ("SW1: %x SW2: %x HW2: %x\n", sw1, sw2, hw2);
  141. /* To do: interrupt-based I2C handling
  142. if (hw2 & 0x00c00000) {
  143. }
  144. */
  145. if (sw2) {
  146. if (sw2 & (cx18_readl(cx, &cx->scb->cpu2hpu_irq_ack) |
  147. cx18_readl(cx, &cx->scb->cpu2epu_irq_ack)))
  148. wake_up(&cx->mb_cpu_waitq);
  149. if (sw2 & (cx18_readl(cx, &cx->scb->apu2hpu_irq_ack) |
  150. cx18_readl(cx, &cx->scb->apu2epu_irq_ack)))
  151. wake_up(&cx->mb_apu_waitq);
  152. if (sw2 & cx18_readl(cx, &cx->scb->epu2hpu_irq_ack))
  153. wake_up(&cx->mb_epu_waitq);
  154. if (sw2 & cx18_readl(cx, &cx->scb->hpu2epu_irq_ack))
  155. wake_up(&cx->mb_hpu_waitq);
  156. }
  157. if (sw1)
  158. hpu_cmd(cx, sw1);
  159. spin_unlock(&cx->dma_reg_lock);
  160. return (hw2 | sw1 | sw2) ? IRQ_HANDLED : IRQ_NONE;
  161. }