upload tizen1.0 source
[kernel/linux-2.6.36.git] / drivers / media / video / saa7164 / saa7164-bus.c
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  */
27 int 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
61 void 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
87 void 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  */
111 int 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
268 out:
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  */
282 int 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
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;
447 }
448