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