Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 1 | /* |
| 2 | Mantis PCI bridge driver |
| 3 | |
Manu Abraham | 8825a09 | 2009-12-15 09:13:49 -0300 | [diff] [blame] | 4 | Copyright (C) Manu Abraham (abraham.manu@gmail.com) |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 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., 675 Mass Ave, Cambridge, MA 02139, USA. |
| 19 | */ |
| 20 | |
Manu Abraham | b3b9614 | 2009-12-04 05:41:11 -0300 | [diff] [blame] | 21 | #include <linux/kernel.h> |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 22 | #include <asm/page.h> |
| 23 | #include <linux/vmalloc.h> |
Manu Abraham | b3b9614 | 2009-12-04 05:41:11 -0300 | [diff] [blame] | 24 | #include <linux/pci.h> |
| 25 | |
| 26 | #include <asm/irq.h> |
| 27 | #include <linux/signal.h> |
| 28 | #include <linux/sched.h> |
| 29 | #include <linux/interrupt.h> |
| 30 | |
| 31 | #include "dmxdev.h" |
| 32 | #include "dvbdev.h" |
| 33 | #include "dvb_demux.h" |
| 34 | #include "dvb_frontend.h" |
| 35 | #include "dvb_net.h" |
| 36 | |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 37 | #include "mantis_common.h" |
Manu Abraham | b3b9614 | 2009-12-04 05:41:11 -0300 | [diff] [blame] | 38 | #include "mantis_reg.h" |
| 39 | #include "mantis_dma.h" |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 40 | |
| 41 | #define RISC_WRITE (0x01 << 28) |
| 42 | #define RISC_JUMP (0x07 << 28) |
| 43 | #define RISC_IRQ (0x01 << 24) |
| 44 | |
| 45 | #define RISC_STATUS(status) ((((~status) & 0x0f) << 20) | ((status & 0x0f) << 16)) |
Manu Abraham | f5ae4f6 | 2009-12-15 08:47:21 -0300 | [diff] [blame] | 46 | #define RISC_FLUSH() (mantis->risc_pos = 0) |
| 47 | #define RISC_INSTR(opcode) (mantis->risc_cpu[mantis->risc_pos++] = cpu_to_le32(opcode)) |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 48 | |
Manu Abraham | f5ae4f6 | 2009-12-15 08:47:21 -0300 | [diff] [blame] | 49 | #define MANTIS_BUF_SIZE (64 * 1024) |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 50 | #define MANTIS_BLOCK_BYTES (MANTIS_BUF_SIZE >> 4) |
| 51 | #define MANTIS_BLOCK_COUNT (1 << 4) |
| 52 | #define MANTIS_RISC_SIZE PAGE_SIZE |
| 53 | |
| 54 | int mantis_dma_exit(struct mantis_pci *mantis) |
| 55 | { |
| 56 | if (mantis->buf_cpu) { |
Manu Abraham | b3b9614 | 2009-12-04 05:41:11 -0300 | [diff] [blame] | 57 | dprintk(MANTIS_ERROR, 1, |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 58 | "DMA=0x%lx cpu=0x%p size=%d", |
| 59 | (unsigned long) mantis->buf_dma, |
| 60 | mantis->buf_cpu, |
| 61 | MANTIS_BUF_SIZE); |
| 62 | |
| 63 | pci_free_consistent(mantis->pdev, MANTIS_BUF_SIZE, |
| 64 | mantis->buf_cpu, mantis->buf_dma); |
| 65 | |
| 66 | mantis->buf_cpu = NULL; |
| 67 | } |
| 68 | if (mantis->risc_cpu) { |
Manu Abraham | b3b9614 | 2009-12-04 05:41:11 -0300 | [diff] [blame] | 69 | dprintk(MANTIS_ERROR, 1, |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 70 | "RISC=0x%lx cpu=0x%p size=%lx", |
| 71 | (unsigned long) mantis->risc_dma, |
| 72 | mantis->risc_cpu, |
| 73 | MANTIS_RISC_SIZE); |
| 74 | |
| 75 | pci_free_consistent(mantis->pdev, MANTIS_RISC_SIZE, |
| 76 | mantis->risc_cpu, mantis->risc_dma); |
| 77 | |
| 78 | mantis->risc_cpu = NULL; |
| 79 | } |
| 80 | |
| 81 | return 0; |
| 82 | } |
Manu Abraham | b3b9614 | 2009-12-04 05:41:11 -0300 | [diff] [blame] | 83 | EXPORT_SYMBOL_GPL(mantis_dma_exit); |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 84 | |
| 85 | static inline int mantis_alloc_buffers(struct mantis_pci *mantis) |
| 86 | { |
| 87 | if (!mantis->buf_cpu) { |
| 88 | mantis->buf_cpu = pci_alloc_consistent(mantis->pdev, |
| 89 | MANTIS_BUF_SIZE, |
| 90 | &mantis->buf_dma); |
| 91 | if (!mantis->buf_cpu) { |
Manu Abraham | b3b9614 | 2009-12-04 05:41:11 -0300 | [diff] [blame] | 92 | dprintk(MANTIS_ERROR, 1, |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 93 | "DMA buffer allocation failed"); |
| 94 | |
| 95 | goto err; |
| 96 | } |
Manu Abraham | b3b9614 | 2009-12-04 05:41:11 -0300 | [diff] [blame] | 97 | dprintk(MANTIS_ERROR, 1, |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 98 | "DMA=0x%lx cpu=0x%p size=%d", |
| 99 | (unsigned long) mantis->buf_dma, |
| 100 | mantis->buf_cpu, MANTIS_BUF_SIZE); |
| 101 | } |
| 102 | if (!mantis->risc_cpu) { |
| 103 | mantis->risc_cpu = pci_alloc_consistent(mantis->pdev, |
| 104 | MANTIS_RISC_SIZE, |
| 105 | &mantis->risc_dma); |
| 106 | |
| 107 | if (!mantis->risc_cpu) { |
Manu Abraham | b3b9614 | 2009-12-04 05:41:11 -0300 | [diff] [blame] | 108 | dprintk(MANTIS_ERROR, 1, |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 109 | "RISC program allocation failed"); |
| 110 | |
| 111 | mantis_dma_exit(mantis); |
| 112 | |
| 113 | goto err; |
| 114 | } |
Manu Abraham | b3b9614 | 2009-12-04 05:41:11 -0300 | [diff] [blame] | 115 | dprintk(MANTIS_ERROR, 1, |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 116 | "RISC=0x%lx cpu=0x%p size=%lx", |
| 117 | (unsigned long) mantis->risc_dma, |
| 118 | mantis->risc_cpu, MANTIS_RISC_SIZE); |
| 119 | } |
| 120 | |
| 121 | return 0; |
| 122 | err: |
Manu Abraham | b3b9614 | 2009-12-04 05:41:11 -0300 | [diff] [blame] | 123 | dprintk(MANTIS_ERROR, 1, "Out of memory (?) ....."); |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 124 | return -ENOMEM; |
| 125 | } |
| 126 | |
| 127 | static inline int mantis_calc_lines(struct mantis_pci *mantis) |
| 128 | { |
| 129 | mantis->line_bytes = MANTIS_BLOCK_BYTES; |
| 130 | mantis->line_count = MANTIS_BLOCK_COUNT; |
| 131 | |
| 132 | while (mantis->line_bytes > 4095) { |
| 133 | mantis->line_bytes >>= 1; |
| 134 | mantis->line_count <<= 1; |
| 135 | } |
| 136 | |
Manu Abraham | b3b9614 | 2009-12-04 05:41:11 -0300 | [diff] [blame] | 137 | dprintk(MANTIS_DEBUG, 1, "Mantis RISC block bytes=[%d], line bytes=[%d], line count=[%d]", |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 138 | MANTIS_BLOCK_BYTES, mantis->line_bytes, mantis->line_count); |
| 139 | |
| 140 | if (mantis->line_count > 255) { |
Manu Abraham | b3b9614 | 2009-12-04 05:41:11 -0300 | [diff] [blame] | 141 | dprintk(MANTIS_ERROR, 1, "Buffer size error"); |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 142 | return -EINVAL; |
| 143 | } |
| 144 | |
| 145 | return 0; |
| 146 | } |
| 147 | |
| 148 | int mantis_dma_init(struct mantis_pci *mantis) |
| 149 | { |
| 150 | int err = 0; |
| 151 | |
Manu Abraham | b3b9614 | 2009-12-04 05:41:11 -0300 | [diff] [blame] | 152 | dprintk(MANTIS_DEBUG, 1, "Mantis DMA init"); |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 153 | if (mantis_alloc_buffers(mantis) < 0) { |
Manu Abraham | b3b9614 | 2009-12-04 05:41:11 -0300 | [diff] [blame] | 154 | dprintk(MANTIS_ERROR, 1, "Error allocating DMA buffer"); |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 155 | |
Manu Abraham | 3e978a8 | 2009-12-04 05:56:35 -0300 | [diff] [blame] | 156 | /* Stop RISC Engine */ |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 157 | mmwrite(0, MANTIS_DMA_CTL); |
| 158 | |
| 159 | goto err; |
| 160 | } |
Manu Abraham | f5ae4f6 | 2009-12-15 08:47:21 -0300 | [diff] [blame] | 161 | err = mantis_calc_lines(mantis); |
| 162 | if (err < 0) { |
Manu Abraham | b3b9614 | 2009-12-04 05:41:11 -0300 | [diff] [blame] | 163 | dprintk(MANTIS_ERROR, 1, "Mantis calc lines failed"); |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 164 | |
| 165 | goto err; |
| 166 | } |
| 167 | |
| 168 | return 0; |
| 169 | err: |
| 170 | return err; |
| 171 | } |
Manu Abraham | b3b9614 | 2009-12-04 05:41:11 -0300 | [diff] [blame] | 172 | EXPORT_SYMBOL_GPL(mantis_dma_init); |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 173 | |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 174 | static inline void mantis_risc_program(struct mantis_pci *mantis) |
| 175 | { |
| 176 | u32 buf_pos = 0; |
| 177 | u32 line; |
| 178 | |
Manu Abraham | b3b9614 | 2009-12-04 05:41:11 -0300 | [diff] [blame] | 179 | dprintk(MANTIS_DEBUG, 1, "Mantis create RISC program"); |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 180 | RISC_FLUSH(); |
| 181 | |
Manu Abraham | b3b9614 | 2009-12-04 05:41:11 -0300 | [diff] [blame] | 182 | dprintk(MANTIS_DEBUG, 1, "risc len lines %u, bytes per line %u", |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 183 | mantis->line_count, mantis->line_bytes); |
| 184 | |
| 185 | for (line = 0; line < mantis->line_count; line++) { |
Manu Abraham | b3b9614 | 2009-12-04 05:41:11 -0300 | [diff] [blame] | 186 | dprintk(MANTIS_DEBUG, 1, "RISC PROG line=[%d]", line); |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 187 | if (!(buf_pos % MANTIS_BLOCK_BYTES)) { |
| 188 | RISC_INSTR(RISC_WRITE | |
| 189 | RISC_IRQ | |
| 190 | RISC_STATUS(((buf_pos / MANTIS_BLOCK_BYTES) + |
| 191 | (MANTIS_BLOCK_COUNT - 1)) % |
| 192 | MANTIS_BLOCK_COUNT) | |
| 193 | mantis->line_bytes); |
| 194 | } else { |
| 195 | RISC_INSTR(RISC_WRITE | mantis->line_bytes); |
| 196 | } |
| 197 | RISC_INSTR(mantis->buf_dma + buf_pos); |
| 198 | buf_pos += mantis->line_bytes; |
| 199 | } |
| 200 | RISC_INSTR(RISC_JUMP); |
| 201 | RISC_INSTR(mantis->risc_dma); |
| 202 | } |
| 203 | |
| 204 | void mantis_dma_start(struct mantis_pci *mantis) |
| 205 | { |
Manu Abraham | b3b9614 | 2009-12-04 05:41:11 -0300 | [diff] [blame] | 206 | dprintk(MANTIS_DEBUG, 1, "Mantis Start DMA engine"); |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 207 | |
| 208 | mantis_risc_program(mantis); |
David Woodhouse | 4170368 | 2009-12-03 05:47:11 -0300 | [diff] [blame] | 209 | mmwrite(mantis->risc_dma, MANTIS_RISC_START); |
Sigmund Augdal | a0c5906 | 2009-12-04 05:13:21 -0300 | [diff] [blame] | 210 | mmwrite(mmread(MANTIS_GPIF_ADDR) | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR); |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 211 | |
| 212 | mmwrite(0, MANTIS_DMA_CTL); |
| 213 | mantis->last_block = mantis->finished_block = 0; |
| 214 | |
| 215 | mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_RISCI, MANTIS_INT_MASK); |
| 216 | |
| 217 | mmwrite(MANTIS_FIFO_EN | MANTIS_DCAP_EN |
| 218 | | MANTIS_RISC_EN, MANTIS_DMA_CTL); |
| 219 | |
| 220 | } |
| 221 | |
| 222 | void mantis_dma_stop(struct mantis_pci *mantis) |
| 223 | { |
| 224 | u32 stat = 0, mask = 0; |
| 225 | |
| 226 | stat = mmread(MANTIS_INT_STAT); |
| 227 | mask = mmread(MANTIS_INT_MASK); |
Manu Abraham | b3b9614 | 2009-12-04 05:41:11 -0300 | [diff] [blame] | 228 | dprintk(MANTIS_DEBUG, 1, "Mantis Stop DMA engine"); |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 229 | |
Sigmund Augdal | a0c5906 | 2009-12-04 05:13:21 -0300 | [diff] [blame] | 230 | mmwrite((mmread(MANTIS_GPIF_ADDR) & (~(MANTIS_GPIF_HIFRDWRN))), MANTIS_GPIF_ADDR); |
Marko Ristola | e4deee0 | 2009-12-03 05:39:22 -0300 | [diff] [blame] | 231 | |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 232 | mmwrite((mmread(MANTIS_DMA_CTL) & ~(MANTIS_FIFO_EN | |
| 233 | MANTIS_DCAP_EN | |
| 234 | MANTIS_RISC_EN)), MANTIS_DMA_CTL); |
| 235 | |
| 236 | mmwrite(mmread(MANTIS_INT_STAT), MANTIS_INT_STAT); |
| 237 | |
| 238 | mmwrite(mmread(MANTIS_INT_MASK) & ~(MANTIS_INT_RISCI | |
| 239 | MANTIS_INT_RISCEN), MANTIS_INT_MASK); |
| 240 | } |
| 241 | |
| 242 | |
| 243 | void mantis_dma_xfer(unsigned long data) |
| 244 | { |
| 245 | struct mantis_pci *mantis = (struct mantis_pci *) data; |
Manu Abraham | 33c7963 | 2009-12-03 05:44:38 -0300 | [diff] [blame] | 246 | struct mantis_hwconfig *config = mantis->hwconfig; |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 247 | |
| 248 | while (mantis->last_block != mantis->finished_block) { |
Manu Abraham | b3b9614 | 2009-12-04 05:41:11 -0300 | [diff] [blame] | 249 | dprintk(MANTIS_DEBUG, 1, "last block=[%d] finished block=[%d]", |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 250 | mantis->last_block, mantis->finished_block); |
| 251 | |
Manu Abraham | f5ae4f6 | 2009-12-15 08:47:21 -0300 | [diff] [blame] | 252 | (config->ts_size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter) |
Manu Abraham | 41e840b | 2009-12-02 21:57:10 -0300 | [diff] [blame] | 253 | (&mantis->demux, &mantis->buf_cpu[mantis->last_block * MANTIS_BLOCK_BYTES], MANTIS_BLOCK_BYTES); |
| 254 | mantis->last_block = (mantis->last_block + 1) % MANTIS_BLOCK_COUNT; |
| 255 | } |
| 256 | } |