aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/saa7164/saa7164-bus.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/saa7164/saa7164-bus.c')
-rw-r--r--drivers/media/video/saa7164/saa7164-bus.c448
1 files changed, 448 insertions, 0 deletions
diff --git a/drivers/media/video/saa7164/saa7164-bus.c b/drivers/media/video/saa7164/saa7164-bus.c
new file mode 100644
index 000000000000..83a04640a25a
--- /dev/null
+++ b/drivers/media/video/saa7164/saa7164-bus.c
@@ -0,0 +1,448 @@
1/*
2 * Driver for the NXP SAA7164 PCIe bridge
3 *
4 * Copyright (c) 2009 Steven Toth <stoth@kernellabs.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 *
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include "saa7164.h"
23
24/* The message bus to/from the firmware is a ring buffer in PCI address
25 * space. Establish the defaults.
26 */
27int saa7164_bus_setup(struct saa7164_dev *dev)
28{
29 tmComResBusInfo_t *b = &dev->bus;
30
31 mutex_init(&b->lock);
32
33 b->Type = TYPE_BUS_PCIe;
34 b->m_wMaxReqSize = SAA_DEVICE_MAXREQUESTSIZE;
35
36 b->m_pdwSetRing = (u8 *)(dev->bmmio +
37 ((u32)dev->busdesc.CommandRing));
38
39 b->m_dwSizeSetRing = SAA_DEVICE_BUFFERBLOCKSIZE;
40
41 b->m_pdwGetRing = (u8 *)(dev->bmmio +
42 ((u32)dev->busdesc.ResponseRing));
43
44 b->m_dwSizeGetRing = SAA_DEVICE_BUFFERBLOCKSIZE;
45
46 b->m_pdwSetWritePos = (u32 *)((u8 *)(dev->bmmio +
47 ((u32)dev->intfdesc.BARLocation) + (2 * sizeof(u64))));
48
49 b->m_pdwSetReadPos = (u32 *)((u8 *)b->m_pdwSetWritePos +
50 1 * sizeof(u32));
51
52 b->m_pdwGetWritePos = (u32 *)((u8 *)b->m_pdwSetWritePos +
53 2 * sizeof(u32));
54
55 b->m_pdwGetReadPos = (u32 *)((u8 *)b->m_pdwSetWritePos +
56 3 * sizeof(u32));
57
58 return 0;
59}
60
61void saa7164_bus_dump(struct saa7164_dev *dev)
62{
63 tmComResBusInfo_t *b = &dev->bus;
64
65 dprintk(DBGLVL_BUS, "Dumping the bus structure:\n");
66 dprintk(DBGLVL_BUS, " .type = %d\n", b->Type);
67 dprintk(DBGLVL_BUS, " .dev->bmmio = 0x%p\n", dev->bmmio);
68 dprintk(DBGLVL_BUS, " .m_wMaxReqSize = 0x%x\n", b->m_wMaxReqSize);
69 dprintk(DBGLVL_BUS, " .m_pdwSetRing = 0x%p\n", b->m_pdwSetRing);
70 dprintk(DBGLVL_BUS, " .m_dwSizeSetRing = 0x%x\n", b->m_dwSizeSetRing);
71 dprintk(DBGLVL_BUS, " .m_pdwGetRing = 0x%p\n", b->m_pdwGetRing);
72 dprintk(DBGLVL_BUS, " .m_dwSizeGetRing = 0x%x\n", b->m_dwSizeGetRing);
73
74 dprintk(DBGLVL_BUS, " .m_pdwSetWritePos = 0x%p (0x%08x)\n",
75 b->m_pdwSetWritePos, *b->m_pdwSetWritePos);
76
77 dprintk(DBGLVL_BUS, " .m_pdwSetReadPos = 0x%p (0x%08x)\n",
78 b->m_pdwSetReadPos, *b->m_pdwSetReadPos);
79
80 dprintk(DBGLVL_BUS, " .m_pdwGetWritePos = 0x%p (0x%08x)\n",
81 b->m_pdwGetWritePos, *b->m_pdwGetWritePos);
82
83 dprintk(DBGLVL_BUS, " .m_pdwGetReadPos = 0x%p (0x%08x)\n",
84 b->m_pdwGetReadPos, *b->m_pdwGetReadPos);
85}
86
87void saa7164_bus_dumpmsg(struct saa7164_dev *dev, tmComResInfo_t* m, void *buf)
88{
89 dprintk(DBGLVL_BUS, "Dumping msg structure:\n");
90 dprintk(DBGLVL_BUS, " .id = %d\n", m->id);
91 dprintk(DBGLVL_BUS, " .flags = 0x%x\n", m->flags);
92 dprintk(DBGLVL_BUS, " .size = 0x%x\n", m->size);
93 dprintk(DBGLVL_BUS, " .command = 0x%x\n", m->command);
94 dprintk(DBGLVL_BUS, " .controlselector = 0x%x\n", m->controlselector);
95 dprintk(DBGLVL_BUS, " .seqno = %d\n", m->seqno);
96 if (buf)
97 dprintk(DBGLVL_BUS, " .buffer (ignored)\n");
98}
99
100/*
101 * Places a command or a response on the bus. The implementation does not
102 * know if it is a command or a response it just places the data on the
103 * bus depending on the bus information given in the tmComResBusInfo_t
104 * structure. If the command or response does not fit into the bus ring
105 * buffer it will be refused.
106 *
107 * Return Value:
108 * SAA_OK The function executed successfully.
109 * < 0 One or more members are not initialized.
110 */
111int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf)
112{
113 tmComResBusInfo_t *bus = &dev->bus;
114 u32 bytes_to_write, read_distance, timeout, curr_srp, curr_swp;
115 u32 new_swp, space_rem;
116 int ret = SAA_ERR_BAD_PARAMETER;
117
118 if (!msg) {
119 printk(KERN_ERR "%s() !msg\n", __func__);
120 return SAA_ERR_BAD_PARAMETER;
121 }
122
123 dprintk(DBGLVL_BUS, "%s()\n", __func__);
124
125 msg->size = cpu_to_le16(msg->size);
126 msg->command = cpu_to_le16(msg->command);
127 msg->controlselector = cpu_to_le16(msg->controlselector);
128
129 if (msg->size > dev->bus.m_wMaxReqSize) {
130 printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n",
131 __func__);
132 return SAA_ERR_BAD_PARAMETER;
133 }
134
135 if ((msg->size > 0) && (buf == 0)) {
136 printk(KERN_ERR "%s() Missing message buffer\n", __func__);
137 return SAA_ERR_BAD_PARAMETER;
138 }
139
140 /* Lock the bus from any other access */
141 mutex_lock(&bus->lock);
142
143 bytes_to_write = sizeof(*msg) + msg->size;
144 read_distance = 0;
145 timeout = SAA_BUS_TIMEOUT;
146 curr_srp = le32_to_cpu(*bus->m_pdwSetReadPos);
147 curr_swp = le32_to_cpu(*bus->m_pdwSetWritePos);
148
149 /* Deal with ring wrapping issues */
150 if (curr_srp > curr_swp)
151 /* The ring has not wrapped yet */
152 read_distance = curr_srp - curr_swp;
153 else
154 /* Deal with the wrapped ring */
155 read_distance = (curr_srp + bus->m_dwSizeSetRing) - curr_swp;
156
157 dprintk(DBGLVL_BUS, "%s() bytes_to_write = %d\n", __func__,
158 bytes_to_write);
159
160 dprintk(DBGLVL_BUS, "%s() read_distance = %d\n", __func__,
161 read_distance);
162
163 dprintk(DBGLVL_BUS, "%s() curr_srp = %x\n", __func__, curr_srp);
164 dprintk(DBGLVL_BUS, "%s() curr_swp = %x\n", __func__, curr_swp);
165
166 /* Process the msg and write the content onto the bus */
167 while (bytes_to_write >= read_distance) {
168
169 if (timeout-- == 0) {
170 printk(KERN_ERR "%s() bus timeout\n", __func__);
171 ret = SAA_ERR_NO_RESOURCES;
172 goto out;
173 }
174
175 /* TODO: Review this delay, efficient? */
176 /* Wait, allowing the hardware fetch time */
177 mdelay(1);
178
179 /* Check the space usage again */
180 curr_srp = le32_to_cpu(*bus->m_pdwSetReadPos);
181
182 /* Deal with ring wrapping issues */
183 if (curr_srp > curr_swp)
184 /* Read didn't wrap around the buffer */
185 read_distance = curr_srp - curr_swp;
186 else
187 /* Deal with the wrapped ring */
188 read_distance = (curr_srp + bus->m_dwSizeSetRing) -
189 curr_swp;
190
191 }
192
193 /* Calculate the new write position */
194 new_swp = curr_swp + bytes_to_write;
195
196 dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp);
197 dprintk(DBGLVL_BUS, "%s() bus->m_dwSizeSetRing = %x\n", __func__,
198 bus->m_dwSizeSetRing);
199
200 /* Mental Note: line 462 tmmhComResBusPCIe.cpp */
201
202 /* Check if we're going to wrap again */
203 if (new_swp > bus->m_dwSizeSetRing) {
204
205 /* Ring wraps */
206 new_swp -= bus->m_dwSizeSetRing;
207
208 space_rem = bus->m_dwSizeSetRing - curr_swp;
209
210 dprintk(DBGLVL_BUS, "%s() space_rem = %x\n", __func__,
211 space_rem);
212
213 dprintk(DBGLVL_BUS, "%s() sizeof(*msg) = %d\n", __func__,
214 (u32)sizeof(*msg));
215
216 if (space_rem < sizeof(*msg)) {
217 dprintk(DBGLVL_BUS, "%s() tr4\n", __func__);
218
219 /* Split the msg into pieces as the ring wraps */
220 memcpy(bus->m_pdwSetRing + curr_swp, msg, space_rem);
221 memcpy(bus->m_pdwSetRing, (u8 *)msg + space_rem,
222 sizeof(*msg) - space_rem);
223
224 memcpy(bus->m_pdwSetRing + sizeof(*msg) - space_rem,
225 buf, msg->size);
226
227 } else if (space_rem == sizeof(*msg)) {
228 dprintk(DBGLVL_BUS, "%s() tr5\n", __func__);
229
230 /* Additional data at the beginning of the ring */
231 memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
232 memcpy(bus->m_pdwSetRing, buf, msg->size);
233
234 } else {
235 /* Additional data wraps around the ring */
236 memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
237 if (msg->size > 0) {
238 memcpy(bus->m_pdwSetRing + curr_swp +
239 sizeof(*msg), buf, space_rem -
240 sizeof(*msg));
241 memcpy(bus->m_pdwSetRing, (u8 *)buf +
242 space_rem - sizeof(*msg),
243 bytes_to_write - space_rem);
244 }
245
246 }
247
248 } /* (new_swp > bus->m_dwSizeSetRing) */
249 else {
250 dprintk(DBGLVL_BUS, "%s() tr6\n", __func__);
251
252 /* The ring buffer doesn't wrap, two simple copies */
253 memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
254 memcpy(bus->m_pdwSetRing + curr_swp + sizeof(*msg), buf,
255 msg->size);
256 }
257
258 dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp);
259
260 /* TODO: Convert all of the direct PCI writes into
261 * saa7164_writel/b calls for consistency.
262 */
263
264 /* Update the bus write position */
265 *bus->m_pdwSetWritePos = cpu_to_le32(new_swp);
266 ret = SAA_OK;
267
268out:
269 mutex_unlock(&bus->lock);
270 return ret;
271}
272
273/*
274 * Receive a command or a response from the bus. The implementation does not
275 * know if it is a command or a response it simply dequeues the data,
276 * depending on the bus information given in the tmComResBusInfo_t structure.
277 *
278 * Return Value:
279 * 0 The function executed successfully.
280 * < 0 One or more members are not initialized.
281 */
282int saa7164_bus_get(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf,
283 int peekonly)
284{
285 tmComResBusInfo_t *bus = &dev->bus;
286 u32 bytes_to_read, write_distance, curr_grp, curr_gwp,
287 new_grp, buf_size, space_rem;
288 tmComResInfo_t msg_tmp;
289 int ret = SAA_ERR_BAD_PARAMETER;
290
291 if (msg == 0)
292 return ret;
293
294 if (msg->size > dev->bus.m_wMaxReqSize) {
295 printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n",
296 __func__);
297 return ret;
298 }
299
300 if ((peekonly == 0) && (msg->size > 0) && (buf == 0)) {
301 printk(KERN_ERR
302 "%s() Missing msg buf, size should be %d bytes\n",
303 __func__, msg->size);
304 return ret;
305 }
306
307 mutex_lock(&bus->lock);
308
309 /* Peek the bus to see if a msg exists, if it's not what we're expecting
310 * then return cleanly else read the message from the bus.
311 */
312 curr_gwp = le32_to_cpu(*bus->m_pdwGetWritePos);
313 curr_grp = le32_to_cpu(*bus->m_pdwGetReadPos);
314
315 if (curr_gwp == curr_grp) {
316 dprintk(DBGLVL_BUS, "%s() No message on the bus\n", __func__);
317 ret = SAA_ERR_EMPTY;
318 goto out;
319 }
320
321 bytes_to_read = sizeof(*msg);
322
323 /* Calculate write distance to current read position */
324 write_distance = 0;
325 if (curr_gwp >= curr_grp)
326 /* Write doesn't wrap around the ring */
327 write_distance = curr_gwp - curr_grp;
328 else
329 /* Write wraps around the ring */
330 write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp;
331
332 if (bytes_to_read > write_distance) {
333 printk(KERN_ERR "%s() No message/response found\n", __func__);
334 ret = SAA_ERR_INVALID_COMMAND;
335 goto out;
336 }
337
338 /* Calculate the new read position */
339 new_grp = curr_grp + bytes_to_read;
340 if (new_grp > bus->m_dwSizeGetRing) {
341
342 /* Ring wraps */
343 new_grp -= bus->m_dwSizeGetRing;
344 space_rem = bus->m_dwSizeGetRing - curr_grp;
345
346 memcpy(&msg_tmp, bus->m_pdwGetRing + curr_grp, space_rem);
347 memcpy((u8 *)&msg_tmp + space_rem, bus->m_pdwGetRing,
348 bytes_to_read - space_rem);
349
350 } else {
351 /* No wrapping */
352 memcpy(&msg_tmp, bus->m_pdwGetRing + curr_grp, bytes_to_read);
353 }
354
355 /* No need to update the read positions, because this was a peek */
356 /* If the caller specifically want to peek, return */
357 if (peekonly) {
358 memcpy(msg, &msg_tmp, sizeof(*msg));
359 goto peekout;
360 }
361
362 /* Check if the command/response matches what is expected */
363 if ((msg_tmp.id != msg->id) || (msg_tmp.command != msg->command) ||
364 (msg_tmp.controlselector != msg->controlselector) ||
365 (msg_tmp.seqno != msg->seqno) || (msg_tmp.size != msg->size)) {
366
367 printk(KERN_ERR "%s() Unexpected msg miss-match\n", __func__);
368 saa7164_bus_dumpmsg(dev, msg, buf);
369 saa7164_bus_dumpmsg(dev, &msg_tmp, 0);
370 ret = SAA_ERR_INVALID_COMMAND;
371 goto out;
372 }
373
374 /* Get the actual command and response from the bus */
375 buf_size = msg->size;
376
377 bytes_to_read = sizeof(*msg) + msg->size;
378 /* Calculate write distance to current read position */
379 write_distance = 0;
380 if (curr_gwp >= curr_grp)
381 /* Write doesn't wrap around the ring */
382 write_distance = curr_gwp - curr_grp;
383 else
384 /* Write wraps around the ring */
385 write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp;
386
387 if (bytes_to_read > write_distance) {
388 printk(KERN_ERR "%s() Invalid bus state, missing msg "
389 "or mangled ring, faulty H/W / bad code?\n", __func__);
390 ret = SAA_ERR_INVALID_COMMAND;
391 goto out;
392 }
393
394 /* Calculate the new read position */
395 new_grp = curr_grp + bytes_to_read;
396 if (new_grp > bus->m_dwSizeGetRing) {
397
398 /* Ring wraps */
399 new_grp -= bus->m_dwSizeGetRing;
400 space_rem = bus->m_dwSizeGetRing - curr_grp;
401
402 if (space_rem < sizeof(*msg)) {
403 /* msg wraps around the ring */
404 memcpy(msg, bus->m_pdwGetRing + curr_grp, space_rem);
405 memcpy((u8 *)msg + space_rem, bus->m_pdwGetRing,
406 sizeof(*msg) - space_rem);
407 if (buf)
408 memcpy(buf, bus->m_pdwGetRing + sizeof(*msg) -
409 space_rem, buf_size);
410
411 } else if (space_rem == sizeof(*msg)) {
412 memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
413 if (buf)
414 memcpy(buf, bus->m_pdwGetRing, buf_size);
415 } else {
416 /* Additional data wraps around the ring */
417 memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
418 if (buf) {
419 memcpy(buf, bus->m_pdwGetRing + curr_grp +
420 sizeof(*msg), space_rem - sizeof(*msg));
421 memcpy(buf + space_rem - sizeof(*msg),
422 bus->m_pdwGetRing, bytes_to_read -
423 space_rem);
424 }
425
426 }
427
428 } else {
429 /* No wrapping */
430 memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
431 if (buf)
432 memcpy(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg),
433 buf_size);
434 }
435
436 /* Update the read positions, adjusting the ring */
437 *bus->m_pdwGetReadPos = cpu_to_le32(new_grp);
438
439peekout:
440 msg->size = le16_to_cpu(msg->size);
441 msg->command = le16_to_cpu(msg->command);
442 msg->controlselector = le16_to_cpu(msg->controlselector);
443 ret = SAA_OK;
444out:
445 mutex_unlock(&bus->lock);
446 return ret;
447}
448