~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/media/video/saa7164/saa7164-buffer.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Driver for the NXP SAA7164 PCIe bridge
 
3
 *
 
4
 *  Copyright (c) 2010 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 <linux/slab.h>
 
23
 
 
24
#include "saa7164.h"
 
25
 
 
26
/* The PCI address space for buffer handling looks like this:
 
27
 *
 
28
 * +-u32 wide-------------+
 
29
 * |                      +
 
30
 * +-u64 wide------------------------------------+
 
31
 * +                                             +
 
32
 * +----------------------+
 
33
 * | CurrentBufferPtr     + Pointer to current PCI buffer >-+
 
34
 * +----------------------+                                 |
 
35
 * | Unused               +                                 |
 
36
 * +----------------------+                                 |
 
37
 * | Pitch                + = 188 (bytes)                   |
 
38
 * +----------------------+                                 |
 
39
 * | PCI buffer size      + = pitch * number of lines (312) |
 
40
 * +----------------------+                                 |
 
41
 * |0| Buf0 Write Offset  +                                 |
 
42
 * +----------------------+                                 v
 
43
 * |1| Buf1 Write Offset  +                                 |
 
44
 * +----------------------+                                 |
 
45
 * |2| Buf2 Write Offset  +                                 |
 
46
 * +----------------------+                                 |
 
47
 * |3| Buf3 Write Offset  +                                 |
 
48
 * +----------------------+                                 |
 
49
 * ... More write offsets                                   |
 
50
 * +---------------------------------------------+          |
 
51
 * +0| set of ptrs to PCI pagetables             +          |
 
52
 * +---------------------------------------------+          |
 
53
 * +1| set of ptrs to PCI pagetables             + <--------+
 
54
 * +---------------------------------------------+
 
55
 * +2| set of ptrs to PCI pagetables             +
 
56
 * +---------------------------------------------+
 
57
 * +3| set of ptrs to PCI pagetables             + >--+
 
58
 * +---------------------------------------------+    |
 
59
 * ... More buffer pointers                           |  +----------------+
 
60
 *                                                  +->| pt[0] TS data  |
 
61
 *                                                  |  +----------------+
 
62
 *                                                  |
 
63
 *                                                  |  +----------------+
 
64
 *                                                  +->| pt[1] TS data  |
 
65
 *                                                  |  +----------------+
 
66
 *                                                  | etc
 
67
 */
 
68
 
 
69
void saa7164_buffer_display(struct saa7164_buffer *buf)
 
70
{
 
71
        struct saa7164_dev *dev = buf->port->dev;
 
72
        int i;
 
73
 
 
74
        dprintk(DBGLVL_BUF, "%s()   buffer @ 0x%p nr=%d\n",
 
75
                __func__, buf, buf->idx);
 
76
        dprintk(DBGLVL_BUF, "  pci_cpu @ 0x%p    dma @ 0x%08llx len = 0x%x\n",
 
77
                buf->cpu, (long long)buf->dma, buf->pci_size);
 
78
        dprintk(DBGLVL_BUF, "   pt_cpu @ 0x%p pt_dma @ 0x%08llx len = 0x%x\n",
 
79
                buf->pt_cpu, (long long)buf->pt_dma, buf->pt_size);
 
80
 
 
81
        /* Format the Page Table Entries to point into the data buffer */
 
82
        for (i = 0 ; i < SAA7164_PT_ENTRIES; i++) {
 
83
 
 
84
                dprintk(DBGLVL_BUF, "    pt[%02d] = 0x%p -> 0x%llx\n",
 
85
                        i, buf->pt_cpu, (u64)*(buf->pt_cpu));
 
86
 
 
87
        }
 
88
}
 
89
/* Allocate a new buffer structure and associated PCI space in bytes.
 
90
 * len must be a multiple of sizeof(u64)
 
91
 */
 
92
struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_port *port,
 
93
        u32 len)
 
94
{
 
95
        struct tmHWStreamParameters *params = &port->hw_streamingparams;
 
96
        struct saa7164_buffer *buf = NULL;
 
97
        struct saa7164_dev *dev = port->dev;
 
98
        int i;
 
99
 
 
100
        if ((len == 0) || (len >= 65536) || (len % sizeof(u64))) {
 
101
                log_warn("%s() SAA_ERR_BAD_PARAMETER\n", __func__);
 
102
                goto ret;
 
103
        }
 
104
 
 
105
        buf = kzalloc(sizeof(struct saa7164_buffer), GFP_KERNEL);
 
106
        if (!buf) {
 
107
                log_warn("%s() SAA_ERR_NO_RESOURCES\n", __func__);
 
108
                goto ret;
 
109
        }
 
110
 
 
111
        buf->idx = -1;
 
112
        buf->port = port;
 
113
        buf->flags = SAA7164_BUFFER_FREE;
 
114
        buf->pos = 0;
 
115
        buf->actual_size = params->pitch * params->numberoflines;
 
116
        buf->crc = 0;
 
117
        /* TODO: arg len is being ignored */
 
118
        buf->pci_size = SAA7164_PT_ENTRIES * 0x1000;
 
119
        buf->pt_size = (SAA7164_PT_ENTRIES * sizeof(u64)) + 0x1000;
 
120
 
 
121
        /* Allocate contiguous memory */
 
122
        buf->cpu = pci_alloc_consistent(port->dev->pci, buf->pci_size,
 
123
                &buf->dma);
 
124
        if (!buf->cpu)
 
125
                goto fail1;
 
126
 
 
127
        buf->pt_cpu = pci_alloc_consistent(port->dev->pci, buf->pt_size,
 
128
                &buf->pt_dma);
 
129
        if (!buf->pt_cpu)
 
130
                goto fail2;
 
131
 
 
132
        /* init the buffers to a known pattern, easier during debugging */
 
133
        memset_io(buf->cpu, 0xff, buf->pci_size);
 
134
        buf->crc = crc32(0, buf->cpu, buf->actual_size);
 
135
        memset_io(buf->pt_cpu, 0xff, buf->pt_size);
 
136
 
 
137
        dprintk(DBGLVL_BUF, "%s()   allocated buffer @ 0x%p (%d pageptrs)\n",
 
138
                __func__, buf, params->numpagetables);
 
139
        dprintk(DBGLVL_BUF, "  pci_cpu @ 0x%p    dma @ 0x%08lx len = 0x%x\n",
 
140
                buf->cpu, (long)buf->dma, buf->pci_size);
 
141
        dprintk(DBGLVL_BUF, "   pt_cpu @ 0x%p pt_dma @ 0x%08lx len = 0x%x\n",
 
142
                buf->pt_cpu, (long)buf->pt_dma, buf->pt_size);
 
143
 
 
144
        /* Format the Page Table Entries to point into the data buffer */
 
145
        for (i = 0 ; i < params->numpagetables; i++) {
 
146
 
 
147
                *(buf->pt_cpu + i) = buf->dma + (i * 0x1000); /* TODO */
 
148
                dprintk(DBGLVL_BUF, "    pt[%02d] = 0x%p -> 0x%llx\n",
 
149
                        i, buf->pt_cpu, (u64)*(buf->pt_cpu));
 
150
 
 
151
        }
 
152
 
 
153
        goto ret;
 
154
 
 
155
fail2:
 
156
        pci_free_consistent(port->dev->pci, buf->pci_size, buf->cpu, buf->dma);
 
157
fail1:
 
158
        kfree(buf);
 
159
 
 
160
        buf = NULL;
 
161
ret:
 
162
        return buf;
 
163
}
 
164
 
 
165
int saa7164_buffer_dealloc(struct saa7164_buffer *buf)
 
166
{
 
167
        struct saa7164_dev *dev;
 
168
 
 
169
        if (!buf || !buf->port)
 
170
                return SAA_ERR_BAD_PARAMETER;
 
171
        dev = buf->port->dev;
 
172
 
 
173
        dprintk(DBGLVL_BUF, "%s() deallocating buffer @ 0x%p\n",
 
174
                __func__, buf);
 
175
 
 
176
        if (buf->flags != SAA7164_BUFFER_FREE)
 
177
                log_warn(" freeing a non-free buffer\n");
 
178
 
 
179
        pci_free_consistent(dev->pci, buf->pci_size, buf->cpu, buf->dma);
 
180
        pci_free_consistent(dev->pci, buf->pt_size, buf->pt_cpu, buf->pt_dma);
 
181
 
 
182
        kfree(buf);
 
183
 
 
184
        return SAA_OK;
 
185
}
 
186
 
 
187
int saa7164_buffer_zero_offsets(struct saa7164_port *port, int i)
 
188
{
 
189
        struct saa7164_dev *dev = port->dev;
 
190
 
 
191
        if ((i < 0) || (i >= port->hwcfg.buffercount))
 
192
                return -EINVAL;
 
193
 
 
194
        dprintk(DBGLVL_BUF, "%s(idx = %d)\n", __func__, i);
 
195
 
 
196
        saa7164_writel(port->bufoffset + (sizeof(u32) * i), 0);
 
197
 
 
198
        return 0;
 
199
}
 
200
 
 
201
/* Write a buffer into the hardware */
 
202
int saa7164_buffer_activate(struct saa7164_buffer *buf, int i)
 
203
{
 
204
        struct saa7164_port *port = buf->port;
 
205
        struct saa7164_dev *dev = port->dev;
 
206
 
 
207
        if ((i < 0) || (i >= port->hwcfg.buffercount))
 
208
                return -EINVAL;
 
209
 
 
210
        dprintk(DBGLVL_BUF, "%s(idx = %d)\n", __func__, i);
 
211
 
 
212
        buf->idx = i; /* Note of which buffer list index position we occupy */
 
213
        buf->flags = SAA7164_BUFFER_BUSY;
 
214
        buf->pos = 0;
 
215
 
 
216
        /* TODO: Review this in light of 32v64 assignments */
 
217
        saa7164_writel(port->bufoffset + (sizeof(u32) * i), 0);
 
218
        saa7164_writel(port->bufptr32h + ((sizeof(u32) * 2) * i), buf->pt_dma);
 
219
        saa7164_writel(port->bufptr32l + ((sizeof(u32) * 2) * i), 0);
 
220
 
 
221
        dprintk(DBGLVL_BUF, "   buf[%d] offset 0x%llx (0x%x) "
 
222
                "buf 0x%llx/%llx (0x%x/%x) nr=%d\n",
 
223
                buf->idx,
 
224
                (u64)port->bufoffset + (i * sizeof(u32)),
 
225
                saa7164_readl(port->bufoffset + (sizeof(u32) * i)),
 
226
                (u64)port->bufptr32h + ((sizeof(u32) * 2) * i),
 
227
                (u64)port->bufptr32l + ((sizeof(u32) * 2) * i),
 
228
                saa7164_readl(port->bufptr32h + ((sizeof(u32) * i) * 2)),
 
229
                saa7164_readl(port->bufptr32l + ((sizeof(u32) * i) * 2)),
 
230
                buf->idx);
 
231
 
 
232
        return 0;
 
233
}
 
234
 
 
235
int saa7164_buffer_cfg_port(struct saa7164_port *port)
 
236
{
 
237
        struct tmHWStreamParameters *params = &port->hw_streamingparams;
 
238
        struct saa7164_dev *dev = port->dev;
 
239
        struct saa7164_buffer *buf;
 
240
        struct list_head *c, *n;
 
241
        int i = 0;
 
242
 
 
243
        dprintk(DBGLVL_BUF, "%s(port=%d)\n", __func__, port->nr);
 
244
 
 
245
        saa7164_writel(port->bufcounter, 0);
 
246
        saa7164_writel(port->pitch, params->pitch);
 
247
        saa7164_writel(port->bufsize, params->pitch * params->numberoflines);
 
248
 
 
249
        dprintk(DBGLVL_BUF, " configured:\n");
 
250
        dprintk(DBGLVL_BUF, "   lmmio       0x%p\n", dev->lmmio);
 
251
        dprintk(DBGLVL_BUF, "   bufcounter  0x%x = 0x%x\n", port->bufcounter,
 
252
                saa7164_readl(port->bufcounter));
 
253
 
 
254
        dprintk(DBGLVL_BUF, "   pitch       0x%x = %d\n", port->pitch,
 
255
                saa7164_readl(port->pitch));
 
256
 
 
257
        dprintk(DBGLVL_BUF, "   bufsize     0x%x = %d\n", port->bufsize,
 
258
                saa7164_readl(port->bufsize));
 
259
 
 
260
        dprintk(DBGLVL_BUF, "   buffercount = %d\n", port->hwcfg.buffercount);
 
261
        dprintk(DBGLVL_BUF, "   bufoffset = 0x%x\n", port->bufoffset);
 
262
        dprintk(DBGLVL_BUF, "   bufptr32h = 0x%x\n", port->bufptr32h);
 
263
        dprintk(DBGLVL_BUF, "   bufptr32l = 0x%x\n", port->bufptr32l);
 
264
 
 
265
        /* Poke the buffers and offsets into PCI space */
 
266
        mutex_lock(&port->dmaqueue_lock);
 
267
        list_for_each_safe(c, n, &port->dmaqueue.list) {
 
268
                buf = list_entry(c, struct saa7164_buffer, list);
 
269
 
 
270
                if (buf->flags != SAA7164_BUFFER_FREE)
 
271
                        BUG();
 
272
 
 
273
                /* Place the buffer in the h/w queue */
 
274
                saa7164_buffer_activate(buf, i);
 
275
 
 
276
                /* Don't exceed the device maximum # bufs */
 
277
                if (i++ > port->hwcfg.buffercount)
 
278
                        BUG();
 
279
 
 
280
        }
 
281
        mutex_unlock(&port->dmaqueue_lock);
 
282
 
 
283
        return 0;
 
284
}
 
285
 
 
286
struct saa7164_user_buffer *saa7164_buffer_alloc_user(struct saa7164_dev *dev,
 
287
        u32 len)
 
288
{
 
289
        struct saa7164_user_buffer *buf;
 
290
 
 
291
        buf = kzalloc(sizeof(struct saa7164_user_buffer), GFP_KERNEL);
 
292
        if (!buf)
 
293
                return NULL;
 
294
 
 
295
        buf->data = kzalloc(len, GFP_KERNEL);
 
296
 
 
297
        if (!buf->data) {
 
298
                kfree(buf);
 
299
                return NULL;
 
300
        }
 
301
 
 
302
        buf->actual_size = len;
 
303
        buf->pos = 0;
 
304
        buf->crc = 0;
 
305
 
 
306
        dprintk(DBGLVL_BUF, "%s()   allocated user buffer @ 0x%p\n",
 
307
                __func__, buf);
 
308
 
 
309
        return buf;
 
310
}
 
311
 
 
312
void saa7164_buffer_dealloc_user(struct saa7164_user_buffer *buf)
 
313
{
 
314
        if (!buf)
 
315
                return;
 
316
 
 
317
        kfree(buf->data);
 
318
        buf->data = NULL;
 
319
 
 
320
        kfree(buf);
 
321
}
 
322