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 69void 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 */ 92struct 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(buf->cpu, 0xff, buf->pci_size); 134 buf->crc = crc32(0, buf->cpu, buf->actual_size); 135 memset(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 155fail2: 156 pci_free_consistent(port->dev->pci, buf->pci_size, buf->cpu, buf->dma); 157fail1: 158 kfree(buf); 159 160 buf = NULL; 161ret: 162 return buf; 163} 164 165int 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 187int 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 */ 202int 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 235int 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 286struct 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 312void 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 323