1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | Mantis PCI bridge driver |
4 | |
5 | Copyright (C) Manu Abraham (abraham.manu@gmail.com) |
6 | |
7 | */ |
8 | |
9 | #include <linux/kernel.h> |
10 | #include <asm/page.h> |
11 | #include <linux/vmalloc.h> |
12 | #include <linux/pci.h> |
13 | |
14 | #include <asm/irq.h> |
15 | #include <linux/signal.h> |
16 | #include <linux/sched.h> |
17 | #include <linux/interrupt.h> |
18 | |
19 | #include <media/dmxdev.h> |
20 | #include <media/dvbdev.h> |
21 | #include <media/dvb_demux.h> |
22 | #include <media/dvb_frontend.h> |
23 | #include <media/dvb_net.h> |
24 | |
25 | #include "mantis_common.h" |
26 | #include "mantis_reg.h" |
27 | #include "mantis_dma.h" |
28 | |
29 | #define RISC_WRITE (0x01 << 28) |
30 | #define RISC_JUMP (0x07 << 28) |
31 | #define RISC_IRQ (0x01 << 24) |
32 | |
33 | #define RISC_STATUS(status) ((((~status) & 0x0f) << 20) | ((status & 0x0f) << 16)) |
34 | #define RISC_FLUSH(risc_pos) (risc_pos = 0) |
35 | #define RISC_INSTR(risc_pos, opcode) (mantis->risc_cpu[risc_pos++] = cpu_to_le32(opcode)) |
36 | |
37 | #define MANTIS_BUF_SIZE (64 * 1024) |
38 | #define MANTIS_BLOCK_BYTES (MANTIS_BUF_SIZE / 4) |
39 | #define MANTIS_DMA_TR_BYTES (2 * 1024) /* upper limit: 4095 bytes. */ |
40 | #define MANTIS_BLOCK_COUNT (MANTIS_BUF_SIZE / MANTIS_BLOCK_BYTES) |
41 | |
42 | #define MANTIS_DMA_TR_UNITS (MANTIS_BLOCK_BYTES / MANTIS_DMA_TR_BYTES) |
43 | /* MANTIS_BUF_SIZE / MANTIS_DMA_TR_UNITS must not exceed MANTIS_RISC_SIZE (4k RISC cmd buffer) */ |
44 | #define MANTIS_RISC_SIZE PAGE_SIZE /* RISC program must fit here. */ |
45 | |
46 | int mantis_dma_exit(struct mantis_pci *mantis) |
47 | { |
48 | if (mantis->buf_cpu) { |
49 | dprintk(MANTIS_ERROR, 1, |
50 | "DMA=0x%lx cpu=0x%p size=%d" , |
51 | (unsigned long) mantis->buf_dma, |
52 | mantis->buf_cpu, |
53 | MANTIS_BUF_SIZE); |
54 | |
55 | dma_free_coherent(dev: &mantis->pdev->dev, MANTIS_BUF_SIZE, |
56 | cpu_addr: mantis->buf_cpu, dma_handle: mantis->buf_dma); |
57 | |
58 | mantis->buf_cpu = NULL; |
59 | } |
60 | if (mantis->risc_cpu) { |
61 | dprintk(MANTIS_ERROR, 1, |
62 | "RISC=0x%lx cpu=0x%p size=%lx" , |
63 | (unsigned long) mantis->risc_dma, |
64 | mantis->risc_cpu, |
65 | MANTIS_RISC_SIZE); |
66 | |
67 | dma_free_coherent(dev: &mantis->pdev->dev, MANTIS_RISC_SIZE, |
68 | cpu_addr: mantis->risc_cpu, dma_handle: mantis->risc_dma); |
69 | |
70 | mantis->risc_cpu = NULL; |
71 | } |
72 | |
73 | return 0; |
74 | } |
75 | EXPORT_SYMBOL_GPL(mantis_dma_exit); |
76 | |
77 | static inline int mantis_alloc_buffers(struct mantis_pci *mantis) |
78 | { |
79 | if (!mantis->buf_cpu) { |
80 | mantis->buf_cpu = dma_alloc_coherent(dev: &mantis->pdev->dev, |
81 | MANTIS_BUF_SIZE, |
82 | dma_handle: &mantis->buf_dma, GFP_KERNEL); |
83 | if (!mantis->buf_cpu) { |
84 | dprintk(MANTIS_ERROR, 1, |
85 | "DMA buffer allocation failed" ); |
86 | |
87 | goto err; |
88 | } |
89 | dprintk(MANTIS_ERROR, 1, |
90 | "DMA=0x%lx cpu=0x%p size=%d" , |
91 | (unsigned long) mantis->buf_dma, |
92 | mantis->buf_cpu, MANTIS_BUF_SIZE); |
93 | } |
94 | if (!mantis->risc_cpu) { |
95 | mantis->risc_cpu = dma_alloc_coherent(dev: &mantis->pdev->dev, |
96 | MANTIS_RISC_SIZE, |
97 | dma_handle: &mantis->risc_dma, GFP_KERNEL); |
98 | |
99 | if (!mantis->risc_cpu) { |
100 | dprintk(MANTIS_ERROR, 1, |
101 | "RISC program allocation failed" ); |
102 | |
103 | mantis_dma_exit(mantis); |
104 | |
105 | goto err; |
106 | } |
107 | dprintk(MANTIS_ERROR, 1, |
108 | "RISC=0x%lx cpu=0x%p size=%lx" , |
109 | (unsigned long) mantis->risc_dma, |
110 | mantis->risc_cpu, MANTIS_RISC_SIZE); |
111 | } |
112 | |
113 | return 0; |
114 | err: |
115 | dprintk(MANTIS_ERROR, 1, "Out of memory (?) ....." ); |
116 | return -ENOMEM; |
117 | } |
118 | |
119 | int mantis_dma_init(struct mantis_pci *mantis) |
120 | { |
121 | int err; |
122 | |
123 | dprintk(MANTIS_DEBUG, 1, "Mantis DMA init" ); |
124 | err = mantis_alloc_buffers(mantis); |
125 | if (err < 0) { |
126 | dprintk(MANTIS_ERROR, 1, "Error allocating DMA buffer" ); |
127 | |
128 | /* Stop RISC Engine */ |
129 | mmwrite(0, MANTIS_DMA_CTL); |
130 | |
131 | return err; |
132 | } |
133 | |
134 | return 0; |
135 | } |
136 | EXPORT_SYMBOL_GPL(mantis_dma_init); |
137 | |
138 | static inline void mantis_risc_program(struct mantis_pci *mantis) |
139 | { |
140 | u32 buf_pos = 0; |
141 | u32 line, step; |
142 | u32 risc_pos; |
143 | |
144 | dprintk(MANTIS_DEBUG, 1, "Mantis create RISC program" ); |
145 | RISC_FLUSH(risc_pos); |
146 | |
147 | dprintk(MANTIS_DEBUG, 1, "risc len lines %u, bytes per line %u, bytes per DMA tr %u" , |
148 | MANTIS_BLOCK_COUNT, MANTIS_BLOCK_BYTES, MANTIS_DMA_TR_BYTES); |
149 | |
150 | for (line = 0; line < MANTIS_BLOCK_COUNT; line++) { |
151 | for (step = 0; step < MANTIS_DMA_TR_UNITS; step++) { |
152 | dprintk(MANTIS_DEBUG, 1, "RISC PROG line=[%d], step=[%d]" , line, step); |
153 | if (step == 0) { |
154 | RISC_INSTR(risc_pos, RISC_WRITE | |
155 | RISC_IRQ | |
156 | RISC_STATUS(line) | |
157 | MANTIS_DMA_TR_BYTES); |
158 | } else { |
159 | RISC_INSTR(risc_pos, RISC_WRITE | MANTIS_DMA_TR_BYTES); |
160 | } |
161 | RISC_INSTR(risc_pos, mantis->buf_dma + buf_pos); |
162 | buf_pos += MANTIS_DMA_TR_BYTES; |
163 | } |
164 | } |
165 | RISC_INSTR(risc_pos, RISC_JUMP); |
166 | RISC_INSTR(risc_pos, mantis->risc_dma); |
167 | } |
168 | |
169 | void mantis_dma_start(struct mantis_pci *mantis) |
170 | { |
171 | dprintk(MANTIS_DEBUG, 1, "Mantis Start DMA engine" ); |
172 | |
173 | mantis_risc_program(mantis); |
174 | mmwrite(mantis->risc_dma, MANTIS_RISC_START); |
175 | mmwrite(mmread(MANTIS_GPIF_ADDR) | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR); |
176 | |
177 | mmwrite(0, MANTIS_DMA_CTL); |
178 | mantis->last_block = mantis->busy_block = 0; |
179 | |
180 | mantis_unmask_ints(mantis, MANTIS_INT_RISCI); |
181 | |
182 | mmwrite(MANTIS_FIFO_EN | MANTIS_DCAP_EN |
183 | | MANTIS_RISC_EN, MANTIS_DMA_CTL); |
184 | |
185 | } |
186 | |
187 | void mantis_dma_stop(struct mantis_pci *mantis) |
188 | { |
189 | dprintk(MANTIS_DEBUG, 1, "Mantis Stop DMA engine" ); |
190 | |
191 | mmwrite((mmread(MANTIS_GPIF_ADDR) & (~(MANTIS_GPIF_HIFRDWRN))), MANTIS_GPIF_ADDR); |
192 | |
193 | mmwrite((mmread(MANTIS_DMA_CTL) & ~(MANTIS_FIFO_EN | |
194 | MANTIS_DCAP_EN | |
195 | MANTIS_RISC_EN)), MANTIS_DMA_CTL); |
196 | |
197 | mmwrite(mmread(MANTIS_INT_STAT), MANTIS_INT_STAT); |
198 | |
199 | mantis_mask_ints(mantis, MANTIS_INT_RISCI | MANTIS_INT_RISCEN); |
200 | } |
201 | |
202 | |
203 | void mantis_dma_xfer(struct tasklet_struct *t) |
204 | { |
205 | struct mantis_pci *mantis = from_tasklet(mantis, t, tasklet); |
206 | struct mantis_hwconfig *config = mantis->hwconfig; |
207 | |
208 | while (mantis->last_block != mantis->busy_block) { |
209 | dprintk(MANTIS_DEBUG, 1, "last block=[%d] finished block=[%d]" , |
210 | mantis->last_block, mantis->busy_block); |
211 | |
212 | (config->ts_size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter) |
213 | (&mantis->demux, &mantis->buf_cpu[mantis->last_block * MANTIS_BLOCK_BYTES], MANTIS_BLOCK_BYTES); |
214 | mantis->last_block = (mantis->last_block + 1) % MANTIS_BLOCK_COUNT; |
215 | } |
216 | } |
217 | |