Merge branch 'fix/hda' of git://github.com/tiwai/sound
[pandora-kernel.git] / drivers / staging / solo6x10 / p2m.c
1 /*
2  * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
3  * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #include <linux/kernel.h>
21 #include <linux/slab.h>
22 #include <linux/scatterlist.h>
23 #include "solo6x10.h"
24
25 /* #define SOLO_TEST_P2M */
26
27 int solo_p2m_dma(struct solo_dev *solo_dev, u8 id, int wr,
28                  void *sys_addr, u32 ext_addr, u32 size)
29 {
30         dma_addr_t dma_addr;
31         int ret;
32
33         WARN_ON(!size);
34         BUG_ON(id >= SOLO_NR_P2M);
35
36         if (!size)
37                 return -EINVAL;
38
39         dma_addr = pci_map_single(solo_dev->pdev, sys_addr, size,
40                                   wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
41
42         ret = solo_p2m_dma_t(solo_dev, id, wr, dma_addr, ext_addr, size);
43
44         pci_unmap_single(solo_dev->pdev, dma_addr, size,
45                          wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
46
47         return ret;
48 }
49
50 int solo_p2m_dma_t(struct solo_dev *solo_dev, u8 id, int wr,
51                    dma_addr_t dma_addr, u32 ext_addr, u32 size)
52 {
53         struct p2m_desc *desc = kzalloc(sizeof(*desc) * 2, GFP_DMA);
54         int ret;
55
56         if (desc == NULL)
57                 return -ENOMEM;
58
59         solo_p2m_push_desc(&desc[1], wr, dma_addr, ext_addr, size, 0, 0);
60         ret = solo_p2m_dma_desc(solo_dev, id, desc, 2);
61         kfree(desc);
62
63         return ret;
64 }
65
66 void solo_p2m_push_desc(struct p2m_desc *desc, int wr, dma_addr_t dma_addr,
67                         u32 ext_addr, u32 size, int repeat, u32 ext_size)
68 {
69         desc->ta = cpu_to_le32(dma_addr);
70         desc->fa = cpu_to_le32(ext_addr);
71
72         desc->ext = cpu_to_le32(SOLO_P2M_COPY_SIZE(size >> 2));
73         desc->ctrl = cpu_to_le32(SOLO_P2M_BURST_SIZE(SOLO_P2M_BURST_256) |
74                                  (wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON);
75
76         /* Ext size only matters when we're repeating */
77         if (repeat) {
78                 desc->ext |= cpu_to_le32(SOLO_P2M_EXT_INC(ext_size >> 2));
79                 desc->ctrl |=  cpu_to_le32(SOLO_P2M_PCI_INC(size >> 2) |
80                                            SOLO_P2M_REPEAT(repeat));
81         }
82 }
83
84 int solo_p2m_dma_desc(struct solo_dev *solo_dev, u8 id,
85                       struct p2m_desc *desc, int desc_count)
86 {
87         struct solo_p2m_dev *p2m_dev;
88         unsigned int timeout;
89         int ret = 0;
90         u32 config = 0;
91         dma_addr_t desc_dma = 0;
92
93         BUG_ON(id >= SOLO_NR_P2M);
94         BUG_ON(!desc_count || desc_count > SOLO_NR_P2M_DESC);
95
96         p2m_dev = &solo_dev->p2m_dev[id];
97
98         mutex_lock(&p2m_dev->mutex);
99
100         solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0);
101
102         INIT_COMPLETION(p2m_dev->completion);
103         p2m_dev->error = 0;
104
105         /* Enable the descriptors */
106         config = solo_reg_read(solo_dev, SOLO_P2M_CONFIG(id));
107         desc_dma = pci_map_single(solo_dev->pdev, desc,
108                                   desc_count * sizeof(*desc),
109                                   PCI_DMA_TODEVICE);
110         solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(id), desc_dma);
111         solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(id), desc_count - 1);
112         solo_reg_write(solo_dev, SOLO_P2M_CONFIG(id), config |
113                        SOLO_P2M_DESC_MODE);
114
115         /* Should have all descriptors completed from one interrupt */
116         timeout = wait_for_completion_timeout(&p2m_dev->completion, HZ);
117
118         solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0);
119
120         /* Reset back to non-descriptor mode */
121         solo_reg_write(solo_dev, SOLO_P2M_CONFIG(id), config);
122         solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(id), 0);
123         solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(id), 0);
124         pci_unmap_single(solo_dev->pdev, desc_dma,
125                          desc_count * sizeof(*desc),
126                          PCI_DMA_TODEVICE);
127
128         if (p2m_dev->error)
129                 ret = -EIO;
130         else if (timeout == 0)
131                 ret = -EAGAIN;
132
133         mutex_unlock(&p2m_dev->mutex);
134
135         WARN_ON_ONCE(ret);
136
137         return ret;
138 }
139
140 int solo_p2m_dma_sg(struct solo_dev *solo_dev, u8 id,
141                     struct p2m_desc *pdesc, int wr,
142                     struct scatterlist *sg, u32 sg_off,
143                     u32 ext_addr, u32 size)
144 {
145         int i;
146         int idx;
147
148         BUG_ON(id >= SOLO_NR_P2M);
149
150         if (WARN_ON_ONCE(!size))
151                 return -EINVAL;
152
153         memset(pdesc, 0, sizeof(*pdesc));
154
155         /* Should rewrite this to handle > SOLO_NR_P2M_DESC transactions */
156         for (i = 0, idx = 1; idx < SOLO_NR_P2M_DESC && sg && size > 0;
157              i++, sg = sg_next(sg)) {
158                 struct p2m_desc *desc = &pdesc[idx];
159                 u32 sg_len = sg_dma_len(sg);
160                 u32 len;
161
162                 if (sg_off >= sg_len) {
163                         sg_off -= sg_len;
164                         continue;
165                 }
166
167                 sg_len -= sg_off;
168                 len = min(sg_len, size);
169
170                 solo_p2m_push_desc(desc, wr, sg_dma_address(sg) + sg_off,
171                                    ext_addr, len, 0, 0);
172
173                 size -= len;
174                 ext_addr += len;
175                 idx++;
176
177                 sg_off = 0;
178         }
179
180         WARN_ON_ONCE(size || i >= SOLO_NR_P2M_DESC);
181
182         return solo_p2m_dma_desc(solo_dev, id, pdesc, idx);
183 }
184
185 #ifdef SOLO_TEST_P2M
186
187 #define P2M_TEST_CHAR           0xbe
188
189 static unsigned long long p2m_test(struct solo_dev *solo_dev, u8 id,
190                                    u32 base, int size)
191 {
192         u8 *wr_buf;
193         u8 *rd_buf;
194         int i;
195         unsigned long long err_cnt = 0;
196
197         wr_buf = kmalloc(size, GFP_KERNEL);
198         if (!wr_buf) {
199                 printk(SOLO6X10_NAME ": Failed to malloc for p2m_test\n");
200                 return size;
201         }
202
203         rd_buf = kmalloc(size, GFP_KERNEL);
204         if (!rd_buf) {
205                 printk(SOLO6X10_NAME ": Failed to malloc for p2m_test\n");
206                 kfree(wr_buf);
207                 return size;
208         }
209
210         memset(wr_buf, P2M_TEST_CHAR, size);
211         memset(rd_buf, P2M_TEST_CHAR + 1, size);
212
213         solo_p2m_dma(solo_dev, id, 1, wr_buf, base, size);
214         solo_p2m_dma(solo_dev, id, 0, rd_buf, base, size);
215
216         for (i = 0; i < size; i++)
217                 if (wr_buf[i] != rd_buf[i])
218                         err_cnt++;
219
220         kfree(wr_buf);
221         kfree(rd_buf);
222
223         return err_cnt;
224 }
225
226 #define TEST_CHUNK_SIZE         (8 * 1024)
227
228 static void run_p2m_test(struct solo_dev *solo_dev)
229 {
230         unsigned long long errs = 0;
231         u32 size = SOLO_JPEG_EXT_ADDR(solo_dev) + SOLO_JPEG_EXT_SIZE(solo_dev);
232         int i, d;
233
234         printk(KERN_WARNING "%s: Testing %u bytes of external ram\n",
235                SOLO6X10_NAME, size);
236
237         for (i = 0; i < size; i += TEST_CHUNK_SIZE)
238                 for (d = 0; d < 4; d++)
239                         errs += p2m_test(solo_dev, d, i, TEST_CHUNK_SIZE);
240
241         printk(KERN_WARNING "%s: Found %llu errors during p2m test\n",
242                SOLO6X10_NAME, errs);
243
244         return;
245 }
246 #else
247 #define run_p2m_test(__solo)    do {} while (0)
248 #endif
249
250 void solo_p2m_isr(struct solo_dev *solo_dev, int id)
251 {
252         struct solo_p2m_dev *p2m_dev = &solo_dev->p2m_dev[id];
253
254         solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_P2M(id));
255
256         complete(&p2m_dev->completion);
257 }
258
259 void solo_p2m_error_isr(struct solo_dev *solo_dev, u32 status)
260 {
261         struct solo_p2m_dev *p2m_dev;
262         int i;
263
264         if (!(status & SOLO_PCI_ERR_P2M))
265                 return;
266
267         for (i = 0; i < SOLO_NR_P2M; i++) {
268                 p2m_dev = &solo_dev->p2m_dev[i];
269                 p2m_dev->error = 1;
270                 solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
271                 complete(&p2m_dev->completion);
272         }
273 }
274
275 void solo_p2m_exit(struct solo_dev *solo_dev)
276 {
277         int i;
278
279         for (i = 0; i < SOLO_NR_P2M; i++)
280                 solo_irq_off(solo_dev, SOLO_IRQ_P2M(i));
281 }
282
283 int solo_p2m_init(struct solo_dev *solo_dev)
284 {
285         struct solo_p2m_dev *p2m_dev;
286         int i;
287
288         for (i = 0; i < SOLO_NR_P2M; i++) {
289                 p2m_dev = &solo_dev->p2m_dev[i];
290
291                 mutex_init(&p2m_dev->mutex);
292                 init_completion(&p2m_dev->completion);
293
294                 solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
295                 solo_reg_write(solo_dev, SOLO_P2M_CONFIG(i),
296                                SOLO_P2M_CSC_16BIT_565 |
297                                SOLO_P2M_DMA_INTERVAL(3) |
298                                SOLO_P2M_DESC_INTR_OPT |
299                                SOLO_P2M_PCI_MASTER_MODE);
300                 solo_irq_on(solo_dev, SOLO_IRQ_P2M(i));
301         }
302
303         run_p2m_test(solo_dev);
304
305         return 0;
306 }