Linux 2.6.34-rc3
[pohmelfs.git] / drivers / media / video / saa7164 / saa7164-bus.c
blob83a04640a25a6fbaafc518165bda72431868632e
1 /*
2 * Driver for the NXP SAA7164 PCIe bridge
4 * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
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.
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
15 * GNU General Public License for more details.
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.
22 #include "saa7164.h"
24 /* The message bus to/from the firmware is a ring buffer in PCI address
25 * space. Establish the defaults.
27 int saa7164_bus_setup(struct saa7164_dev *dev)
29 tmComResBusInfo_t *b = &dev->bus;
31 mutex_init(&b->lock);
33 b->Type = TYPE_BUS_PCIe;
34 b->m_wMaxReqSize = SAA_DEVICE_MAXREQUESTSIZE;
36 b->m_pdwSetRing = (u8 *)(dev->bmmio +
37 ((u32)dev->busdesc.CommandRing));
39 b->m_dwSizeSetRing = SAA_DEVICE_BUFFERBLOCKSIZE;
41 b->m_pdwGetRing = (u8 *)(dev->bmmio +
42 ((u32)dev->busdesc.ResponseRing));
44 b->m_dwSizeGetRing = SAA_DEVICE_BUFFERBLOCKSIZE;
46 b->m_pdwSetWritePos = (u32 *)((u8 *)(dev->bmmio +
47 ((u32)dev->intfdesc.BARLocation) + (2 * sizeof(u64))));
49 b->m_pdwSetReadPos = (u32 *)((u8 *)b->m_pdwSetWritePos +
50 1 * sizeof(u32));
52 b->m_pdwGetWritePos = (u32 *)((u8 *)b->m_pdwSetWritePos +
53 2 * sizeof(u32));
55 b->m_pdwGetReadPos = (u32 *)((u8 *)b->m_pdwSetWritePos +
56 3 * sizeof(u32));
58 return 0;
61 void saa7164_bus_dump(struct saa7164_dev *dev)
63 tmComResBusInfo_t *b = &dev->bus;
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);
74 dprintk(DBGLVL_BUS, " .m_pdwSetWritePos = 0x%p (0x%08x)\n",
75 b->m_pdwSetWritePos, *b->m_pdwSetWritePos);
77 dprintk(DBGLVL_BUS, " .m_pdwSetReadPos = 0x%p (0x%08x)\n",
78 b->m_pdwSetReadPos, *b->m_pdwSetReadPos);
80 dprintk(DBGLVL_BUS, " .m_pdwGetWritePos = 0x%p (0x%08x)\n",
81 b->m_pdwGetWritePos, *b->m_pdwGetWritePos);
83 dprintk(DBGLVL_BUS, " .m_pdwGetReadPos = 0x%p (0x%08x)\n",
84 b->m_pdwGetReadPos, *b->m_pdwGetReadPos);
87 void saa7164_bus_dumpmsg(struct saa7164_dev *dev, tmComResInfo_t* m, void *buf)
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");
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.
107 * Return Value:
108 * SAA_OK The function executed successfully.
109 * < 0 One or more members are not initialized.
111 int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf)
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;
118 if (!msg) {
119 printk(KERN_ERR "%s() !msg\n", __func__);
120 return SAA_ERR_BAD_PARAMETER;
123 dprintk(DBGLVL_BUS, "%s()\n", __func__);
125 msg->size = cpu_to_le16(msg->size);
126 msg->command = cpu_to_le16(msg->command);
127 msg->controlselector = cpu_to_le16(msg->controlselector);
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;
135 if ((msg->size > 0) && (buf == 0)) {
136 printk(KERN_ERR "%s() Missing message buffer\n", __func__);
137 return SAA_ERR_BAD_PARAMETER;
140 /* Lock the bus from any other access */
141 mutex_lock(&bus->lock);
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);
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;
157 dprintk(DBGLVL_BUS, "%s() bytes_to_write = %d\n", __func__,
158 bytes_to_write);
160 dprintk(DBGLVL_BUS, "%s() read_distance = %d\n", __func__,
161 read_distance);
163 dprintk(DBGLVL_BUS, "%s() curr_srp = %x\n", __func__, curr_srp);
164 dprintk(DBGLVL_BUS, "%s() curr_swp = %x\n", __func__, curr_swp);
166 /* Process the msg and write the content onto the bus */
167 while (bytes_to_write >= read_distance) {
169 if (timeout-- == 0) {
170 printk(KERN_ERR "%s() bus timeout\n", __func__);
171 ret = SAA_ERR_NO_RESOURCES;
172 goto out;
175 /* TODO: Review this delay, efficient? */
176 /* Wait, allowing the hardware fetch time */
177 mdelay(1);
179 /* Check the space usage again */
180 curr_srp = le32_to_cpu(*bus->m_pdwSetReadPos);
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;
193 /* Calculate the new write position */
194 new_swp = curr_swp + bytes_to_write;
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);
200 /* Mental Note: line 462 tmmhComResBusPCIe.cpp */
202 /* Check if we're going to wrap again */
203 if (new_swp > bus->m_dwSizeSetRing) {
205 /* Ring wraps */
206 new_swp -= bus->m_dwSizeSetRing;
208 space_rem = bus->m_dwSizeSetRing - curr_swp;
210 dprintk(DBGLVL_BUS, "%s() space_rem = %x\n", __func__,
211 space_rem);
213 dprintk(DBGLVL_BUS, "%s() sizeof(*msg) = %d\n", __func__,
214 (u32)sizeof(*msg));
216 if (space_rem < sizeof(*msg)) {
217 dprintk(DBGLVL_BUS, "%s() tr4\n", __func__);
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);
224 memcpy(bus->m_pdwSetRing + sizeof(*msg) - space_rem,
225 buf, msg->size);
227 } else if (space_rem == sizeof(*msg)) {
228 dprintk(DBGLVL_BUS, "%s() tr5\n", __func__);
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);
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);
248 } /* (new_swp > bus->m_dwSizeSetRing) */
249 else {
250 dprintk(DBGLVL_BUS, "%s() tr6\n", __func__);
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);
258 dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp);
260 /* TODO: Convert all of the direct PCI writes into
261 * saa7164_writel/b calls for consistency.
264 /* Update the bus write position */
265 *bus->m_pdwSetWritePos = cpu_to_le32(new_swp);
266 ret = SAA_OK;
268 out:
269 mutex_unlock(&bus->lock);
270 return ret;
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.
278 * Return Value:
279 * 0 The function executed successfully.
280 * < 0 One or more members are not initialized.
282 int saa7164_bus_get(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf,
283 int peekonly)
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;
291 if (msg == 0)
292 return ret;
294 if (msg->size > dev->bus.m_wMaxReqSize) {
295 printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n",
296 __func__);
297 return ret;
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;
307 mutex_lock(&bus->lock);
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.
312 curr_gwp = le32_to_cpu(*bus->m_pdwGetWritePos);
313 curr_grp = le32_to_cpu(*bus->m_pdwGetReadPos);
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;
321 bytes_to_read = sizeof(*msg);
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;
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;
338 /* Calculate the new read position */
339 new_grp = curr_grp + bytes_to_read;
340 if (new_grp > bus->m_dwSizeGetRing) {
342 /* Ring wraps */
343 new_grp -= bus->m_dwSizeGetRing;
344 space_rem = bus->m_dwSizeGetRing - curr_grp;
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);
350 } else {
351 /* No wrapping */
352 memcpy(&msg_tmp, bus->m_pdwGetRing + curr_grp, bytes_to_read);
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;
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)) {
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;
374 /* Get the actual command and response from the bus */
375 buf_size = msg->size;
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;
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;
394 /* Calculate the new read position */
395 new_grp = curr_grp + bytes_to_read;
396 if (new_grp > bus->m_dwSizeGetRing) {
398 /* Ring wraps */
399 new_grp -= bus->m_dwSizeGetRing;
400 space_rem = bus->m_dwSizeGetRing - curr_grp;
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);
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);
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);
436 /* Update the read positions, adjusting the ring */
437 *bus->m_pdwGetReadPos = cpu_to_le32(new_grp);
439 peekout:
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;
444 out:
445 mutex_unlock(&bus->lock);
446 return ret;