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