1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | saa7146.o - driver for generic saa7146-based hardware |
4 | |
5 | Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de> |
6 | |
7 | */ |
8 | |
9 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
10 | |
11 | #include <media/drv-intf/saa7146.h> |
12 | #include <linux/module.h> |
13 | |
14 | static int saa7146_num; |
15 | |
16 | unsigned int saa7146_debug; |
17 | |
18 | module_param(saa7146_debug, uint, 0644); |
19 | MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)" ); |
20 | |
21 | #if 0 |
22 | static void dump_registers(struct saa7146_dev* dev) |
23 | { |
24 | int i = 0; |
25 | |
26 | pr_info(" @ %li jiffies:\n" , jiffies); |
27 | for (i = 0; i <= 0x148; i += 4) |
28 | pr_info("0x%03x: 0x%08x\n" , i, saa7146_read(dev, i)); |
29 | } |
30 | #endif |
31 | |
32 | /**************************************************************************** |
33 | * gpio and debi helper functions |
34 | ****************************************************************************/ |
35 | |
36 | void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data) |
37 | { |
38 | u32 value = 0; |
39 | |
40 | if (WARN_ON(port > 3)) |
41 | return; |
42 | |
43 | value = saa7146_read(dev, GPIO_CTRL); |
44 | value &= ~(0xff << (8*port)); |
45 | value |= (data << (8*port)); |
46 | saa7146_write(dev, GPIO_CTRL, value); |
47 | } |
48 | |
49 | /* This DEBI code is based on the saa7146 Stradis driver by Nathan Laredo */ |
50 | static inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev, |
51 | unsigned long us1, unsigned long us2) |
52 | { |
53 | unsigned long timeout; |
54 | int err; |
55 | |
56 | /* wait for registers to be programmed */ |
57 | timeout = jiffies + usecs_to_jiffies(u: us1); |
58 | while (1) { |
59 | err = time_after(jiffies, timeout); |
60 | if (saa7146_read(dev, MC2) & 2) |
61 | break; |
62 | if (err) { |
63 | pr_debug("%s: %s timed out while waiting for registers getting programmed\n" , |
64 | dev->name, __func__); |
65 | return -ETIMEDOUT; |
66 | } |
67 | msleep(msecs: 1); |
68 | } |
69 | |
70 | /* wait for transfer to complete */ |
71 | timeout = jiffies + usecs_to_jiffies(u: us2); |
72 | while (1) { |
73 | err = time_after(jiffies, timeout); |
74 | if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S)) |
75 | break; |
76 | saa7146_read(dev, MC2); |
77 | if (err) { |
78 | DEB_S("%s: %s timed out while waiting for transfer completion\n" , |
79 | dev->name, __func__); |
80 | return -ETIMEDOUT; |
81 | } |
82 | msleep(msecs: 1); |
83 | } |
84 | |
85 | return 0; |
86 | } |
87 | |
88 | static inline int saa7146_wait_for_debi_done_busyloop(struct saa7146_dev *dev, |
89 | unsigned long us1, unsigned long us2) |
90 | { |
91 | unsigned long loops; |
92 | |
93 | /* wait for registers to be programmed */ |
94 | loops = us1; |
95 | while (1) { |
96 | if (saa7146_read(dev, MC2) & 2) |
97 | break; |
98 | if (!loops--) { |
99 | pr_err("%s: %s timed out while waiting for registers getting programmed\n" , |
100 | dev->name, __func__); |
101 | return -ETIMEDOUT; |
102 | } |
103 | udelay(1); |
104 | } |
105 | |
106 | /* wait for transfer to complete */ |
107 | loops = us2 / 5; |
108 | while (1) { |
109 | if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S)) |
110 | break; |
111 | saa7146_read(dev, MC2); |
112 | if (!loops--) { |
113 | DEB_S("%s: %s timed out while waiting for transfer completion\n" , |
114 | dev->name, __func__); |
115 | return -ETIMEDOUT; |
116 | } |
117 | udelay(5); |
118 | } |
119 | |
120 | return 0; |
121 | } |
122 | |
123 | int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop) |
124 | { |
125 | if (nobusyloop) |
126 | return saa7146_wait_for_debi_done_sleep(dev, us1: 50000, us2: 250000); |
127 | else |
128 | return saa7146_wait_for_debi_done_busyloop(dev, us1: 50000, us2: 250000); |
129 | } |
130 | |
131 | /**************************************************************************** |
132 | * general helper functions |
133 | ****************************************************************************/ |
134 | |
135 | /* this is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c |
136 | make sure virt has been allocated with vmalloc_32(), otherwise return NULL |
137 | on highmem machines */ |
138 | static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages) |
139 | { |
140 | struct scatterlist *sglist; |
141 | struct page *pg; |
142 | int i; |
143 | |
144 | sglist = kmalloc_array(n: nr_pages, size: sizeof(struct scatterlist), GFP_KERNEL); |
145 | if (NULL == sglist) |
146 | return NULL; |
147 | sg_init_table(sglist, nr_pages); |
148 | for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { |
149 | pg = vmalloc_to_page(addr: virt); |
150 | if (NULL == pg) |
151 | goto err; |
152 | if (WARN_ON(PageHighMem(pg))) |
153 | goto err; |
154 | sg_set_page(sg: &sglist[i], page: pg, PAGE_SIZE, offset: 0); |
155 | } |
156 | return sglist; |
157 | |
158 | err: |
159 | kfree(objp: sglist); |
160 | return NULL; |
161 | } |
162 | |
163 | /********************************************************************************/ |
164 | /* common page table functions */ |
165 | |
166 | void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt) |
167 | { |
168 | int pages = (length+PAGE_SIZE-1)/PAGE_SIZE; |
169 | void *mem = vmalloc_32(size: length); |
170 | int slen = 0; |
171 | |
172 | if (NULL == mem) |
173 | goto err_null; |
174 | |
175 | if (!(pt->slist = vmalloc_to_sg(virt: mem, nr_pages: pages))) |
176 | goto err_free_mem; |
177 | |
178 | if (saa7146_pgtable_alloc(pci, pt)) |
179 | goto err_free_slist; |
180 | |
181 | pt->nents = pages; |
182 | slen = dma_map_sg(&pci->dev, pt->slist, pt->nents, DMA_FROM_DEVICE); |
183 | if (0 == slen) |
184 | goto err_free_pgtable; |
185 | |
186 | if (0 != saa7146_pgtable_build_single(pci, pt, list: pt->slist, length: slen)) |
187 | goto err_unmap_sg; |
188 | |
189 | return mem; |
190 | |
191 | err_unmap_sg: |
192 | dma_unmap_sg(&pci->dev, pt->slist, pt->nents, DMA_FROM_DEVICE); |
193 | err_free_pgtable: |
194 | saa7146_pgtable_free(pci, pt); |
195 | err_free_slist: |
196 | kfree(objp: pt->slist); |
197 | pt->slist = NULL; |
198 | err_free_mem: |
199 | vfree(addr: mem); |
200 | err_null: |
201 | return NULL; |
202 | } |
203 | |
204 | void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt) |
205 | { |
206 | dma_unmap_sg(&pci->dev, pt->slist, pt->nents, DMA_FROM_DEVICE); |
207 | saa7146_pgtable_free(pci, pt); |
208 | kfree(objp: pt->slist); |
209 | pt->slist = NULL; |
210 | vfree(addr: mem); |
211 | } |
212 | |
213 | void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt) |
214 | { |
215 | if (NULL == pt->cpu) |
216 | return; |
217 | dma_free_coherent(dev: &pci->dev, size: pt->size, cpu_addr: pt->cpu, dma_handle: pt->dma); |
218 | pt->cpu = NULL; |
219 | } |
220 | |
221 | int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt) |
222 | { |
223 | __le32 *cpu; |
224 | dma_addr_t dma_addr = 0; |
225 | |
226 | cpu = dma_alloc_coherent(dev: &pci->dev, PAGE_SIZE, dma_handle: &dma_addr, GFP_KERNEL); |
227 | if (NULL == cpu) { |
228 | return -ENOMEM; |
229 | } |
230 | pt->size = PAGE_SIZE; |
231 | pt->cpu = cpu; |
232 | pt->dma = dma_addr; |
233 | |
234 | return 0; |
235 | } |
236 | |
237 | int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, |
238 | struct scatterlist *list, int sglen) |
239 | { |
240 | struct sg_dma_page_iter dma_iter; |
241 | __le32 *ptr, fill; |
242 | int nr_pages = 0; |
243 | int i; |
244 | |
245 | if (WARN_ON(!sglen) || |
246 | WARN_ON(list->offset > PAGE_SIZE)) |
247 | return -EIO; |
248 | |
249 | /* if we have a user buffer, the first page may not be |
250 | aligned to a page boundary. */ |
251 | pt->offset = list->offset; |
252 | |
253 | ptr = pt->cpu; |
254 | for_each_sg_dma_page(list, &dma_iter, sglen, 0) { |
255 | *ptr++ = cpu_to_le32(sg_page_iter_dma_address(&dma_iter)); |
256 | nr_pages++; |
257 | } |
258 | |
259 | |
260 | /* safety; fill the page table up with the last valid page */ |
261 | fill = *(ptr-1); |
262 | for (i = nr_pages; i < 1024; i++) |
263 | *ptr++ = fill; |
264 | return 0; |
265 | } |
266 | |
267 | /********************************************************************************/ |
268 | /* interrupt handler */ |
269 | static irqreturn_t interrupt_hw(int irq, void *dev_id) |
270 | { |
271 | struct saa7146_dev *dev = dev_id; |
272 | u32 isr; |
273 | u32 ack_isr; |
274 | |
275 | /* read out the interrupt status register */ |
276 | ack_isr = isr = saa7146_read(dev, ISR); |
277 | |
278 | /* is this our interrupt? */ |
279 | if ( 0 == isr ) { |
280 | /* nope, some other device */ |
281 | return IRQ_NONE; |
282 | } |
283 | |
284 | if (dev->ext) { |
285 | if (dev->ext->irq_mask & isr) { |
286 | if (dev->ext->irq_func) |
287 | dev->ext->irq_func(dev, &isr); |
288 | isr &= ~dev->ext->irq_mask; |
289 | } |
290 | } |
291 | if (0 != (isr & (MASK_27))) { |
292 | DEB_INT("irq: RPS0 (0x%08x)\n" , isr); |
293 | if (dev->vv_data && dev->vv_callback) |
294 | dev->vv_callback(dev,isr); |
295 | isr &= ~MASK_27; |
296 | } |
297 | if (0 != (isr & (MASK_28))) { |
298 | if (dev->vv_data && dev->vv_callback) |
299 | dev->vv_callback(dev,isr); |
300 | isr &= ~MASK_28; |
301 | } |
302 | if (0 != (isr & (MASK_16|MASK_17))) { |
303 | SAA7146_IER_DISABLE(x: dev, MASK_16|MASK_17); |
304 | /* only wake up if we expect something */ |
305 | if (0 != dev->i2c_op) { |
306 | dev->i2c_op = 0; |
307 | wake_up(&dev->i2c_wq); |
308 | } else { |
309 | u32 psr = saa7146_read(dev, PSR); |
310 | u32 ssr = saa7146_read(dev, SSR); |
311 | pr_warn("%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n" , |
312 | dev->name, isr, psr, ssr); |
313 | } |
314 | isr &= ~(MASK_16|MASK_17); |
315 | } |
316 | if( 0 != isr ) { |
317 | ERR("warning: interrupt enabled, but not handled properly.(0x%08x)\n" , |
318 | isr); |
319 | ERR("disabling interrupt source(s)!\n" ); |
320 | SAA7146_IER_DISABLE(x: dev,y: isr); |
321 | } |
322 | saa7146_write(dev, ISR, ack_isr); |
323 | return IRQ_HANDLED; |
324 | } |
325 | |
326 | /*********************************************************************************/ |
327 | /* configuration-functions */ |
328 | |
329 | static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent) |
330 | { |
331 | struct saa7146_pci_extension_data *pci_ext = (struct saa7146_pci_extension_data *)ent->driver_data; |
332 | struct saa7146_extension *ext = pci_ext->ext; |
333 | struct saa7146_dev *dev; |
334 | int err = -ENOMEM; |
335 | |
336 | /* clear out mem for sure */ |
337 | dev = kzalloc(size: sizeof(struct saa7146_dev), GFP_KERNEL); |
338 | if (!dev) { |
339 | ERR("out of memory\n" ); |
340 | goto out; |
341 | } |
342 | |
343 | /* create a nice device name */ |
344 | sprintf(buf: dev->name, fmt: "saa7146 (%d)" , saa7146_num); |
345 | |
346 | DEB_EE("pci:%p\n" , pci); |
347 | |
348 | err = pci_enable_device(dev: pci); |
349 | if (err < 0) { |
350 | ERR("pci_enable_device() failed\n" ); |
351 | goto err_free; |
352 | } |
353 | |
354 | /* enable bus-mastering */ |
355 | pci_set_master(dev: pci); |
356 | |
357 | dev->pci = pci; |
358 | |
359 | /* get chip-revision; this is needed to enable bug-fixes */ |
360 | dev->revision = pci->revision; |
361 | |
362 | /* remap the memory from virtual to physical address */ |
363 | |
364 | err = pci_request_region(pci, 0, "saa7146" ); |
365 | if (err < 0) |
366 | goto err_disable; |
367 | |
368 | dev->mem = ioremap(pci_resource_start(pci, 0), |
369 | pci_resource_len(pci, 0)); |
370 | if (!dev->mem) { |
371 | ERR("ioremap() failed\n" ); |
372 | err = -ENODEV; |
373 | goto err_release; |
374 | } |
375 | |
376 | /* we don't do a master reset here anymore, it screws up |
377 | some boards that don't have an i2c-eeprom for configuration |
378 | values */ |
379 | /* |
380 | saa7146_write(dev, MC1, MASK_31); |
381 | */ |
382 | |
383 | /* disable all irqs */ |
384 | saa7146_write(dev, IER, 0); |
385 | |
386 | /* shut down all dma transfers and rps tasks */ |
387 | saa7146_write(dev, MC1, 0x30ff0000); |
388 | |
389 | /* clear out any rps-signals pending */ |
390 | saa7146_write(dev, MC2, 0xf8000000); |
391 | |
392 | /* request an interrupt for the saa7146 */ |
393 | err = request_irq(irq: pci->irq, handler: interrupt_hw, IRQF_SHARED, |
394 | name: dev->name, dev); |
395 | if (err < 0) { |
396 | ERR("request_irq() failed\n" ); |
397 | goto err_unmap; |
398 | } |
399 | |
400 | err = -ENOMEM; |
401 | |
402 | /* get memory for various stuff */ |
403 | dev->d_rps0.cpu_addr = dma_alloc_coherent(dev: &pci->dev, SAA7146_RPS_MEM, |
404 | dma_handle: &dev->d_rps0.dma_handle, |
405 | GFP_KERNEL); |
406 | if (!dev->d_rps0.cpu_addr) |
407 | goto err_free_irq; |
408 | |
409 | dev->d_rps1.cpu_addr = dma_alloc_coherent(dev: &pci->dev, SAA7146_RPS_MEM, |
410 | dma_handle: &dev->d_rps1.dma_handle, |
411 | GFP_KERNEL); |
412 | if (!dev->d_rps1.cpu_addr) |
413 | goto err_free_rps0; |
414 | |
415 | dev->d_i2c.cpu_addr = dma_alloc_coherent(dev: &pci->dev, SAA7146_RPS_MEM, |
416 | dma_handle: &dev->d_i2c.dma_handle, GFP_KERNEL); |
417 | if (!dev->d_i2c.cpu_addr) |
418 | goto err_free_rps1; |
419 | |
420 | /* the rest + print status message */ |
421 | |
422 | pr_info("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x)\n" , |
423 | dev->mem, dev->revision, pci->irq, |
424 | pci->subsystem_vendor, pci->subsystem_device); |
425 | dev->ext = ext; |
426 | |
427 | mutex_init(&dev->v4l2_lock); |
428 | spin_lock_init(&dev->int_slock); |
429 | spin_lock_init(&dev->slock); |
430 | |
431 | mutex_init(&dev->i2c_lock); |
432 | |
433 | dev->module = THIS_MODULE; |
434 | init_waitqueue_head(&dev->i2c_wq); |
435 | |
436 | /* set some sane pci arbitrition values */ |
437 | saa7146_write(dev, PCI_BT_V1, 0x1c00101f); |
438 | |
439 | /* TODO: use the status code of the callback */ |
440 | |
441 | err = -ENODEV; |
442 | |
443 | if (ext->probe && ext->probe(dev)) { |
444 | DEB_D("ext->probe() failed for %p. skipping device.\n" , dev); |
445 | goto err_free_i2c; |
446 | } |
447 | |
448 | if (ext->attach(dev, pci_ext)) { |
449 | DEB_D("ext->attach() failed for %p. skipping device.\n" , dev); |
450 | goto err_free_i2c; |
451 | } |
452 | /* V4L extensions will set the pci drvdata to the v4l2_device in the |
453 | attach() above. So for those cards that do not use V4L we have to |
454 | set it explicitly. */ |
455 | pci_set_drvdata(pdev: pci, data: &dev->v4l2_dev); |
456 | |
457 | saa7146_num++; |
458 | |
459 | err = 0; |
460 | out: |
461 | return err; |
462 | |
463 | err_free_i2c: |
464 | dma_free_coherent(dev: &pci->dev, SAA7146_RPS_MEM, cpu_addr: dev->d_i2c.cpu_addr, |
465 | dma_handle: dev->d_i2c.dma_handle); |
466 | err_free_rps1: |
467 | dma_free_coherent(dev: &pci->dev, SAA7146_RPS_MEM, cpu_addr: dev->d_rps1.cpu_addr, |
468 | dma_handle: dev->d_rps1.dma_handle); |
469 | err_free_rps0: |
470 | dma_free_coherent(dev: &pci->dev, SAA7146_RPS_MEM, cpu_addr: dev->d_rps0.cpu_addr, |
471 | dma_handle: dev->d_rps0.dma_handle); |
472 | err_free_irq: |
473 | free_irq(pci->irq, (void *)dev); |
474 | err_unmap: |
475 | iounmap(addr: dev->mem); |
476 | err_release: |
477 | pci_release_region(pci, 0); |
478 | err_disable: |
479 | pci_disable_device(dev: pci); |
480 | err_free: |
481 | kfree(objp: dev); |
482 | goto out; |
483 | } |
484 | |
485 | static void saa7146_remove_one(struct pci_dev *pdev) |
486 | { |
487 | struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev); |
488 | struct saa7146_dev *dev = to_saa7146_dev(v4l2_dev); |
489 | struct { |
490 | void *addr; |
491 | dma_addr_t dma; |
492 | } dev_map[] = { |
493 | { dev->d_i2c.cpu_addr, dev->d_i2c.dma_handle }, |
494 | { dev->d_rps1.cpu_addr, dev->d_rps1.dma_handle }, |
495 | { dev->d_rps0.cpu_addr, dev->d_rps0.dma_handle }, |
496 | { NULL, 0 } |
497 | }, *p; |
498 | |
499 | DEB_EE("dev:%p\n" , dev); |
500 | |
501 | dev->ext->detach(dev); |
502 | |
503 | /* shut down all video dma transfers */ |
504 | saa7146_write(dev, MC1, 0x00ff0000); |
505 | |
506 | /* disable all irqs, release irq-routine */ |
507 | saa7146_write(dev, IER, 0); |
508 | |
509 | free_irq(pdev->irq, dev); |
510 | |
511 | for (p = dev_map; p->addr; p++) |
512 | dma_free_coherent(dev: &pdev->dev, SAA7146_RPS_MEM, cpu_addr: p->addr, |
513 | dma_handle: p->dma); |
514 | |
515 | iounmap(addr: dev->mem); |
516 | pci_release_region(pdev, 0); |
517 | pci_disable_device(dev: pdev); |
518 | kfree(objp: dev); |
519 | |
520 | saa7146_num--; |
521 | } |
522 | |
523 | /*********************************************************************************/ |
524 | /* extension handling functions */ |
525 | |
526 | int saa7146_register_extension(struct saa7146_extension* ext) |
527 | { |
528 | DEB_EE("ext:%p\n" , ext); |
529 | |
530 | ext->driver.name = ext->name; |
531 | ext->driver.id_table = ext->pci_tbl; |
532 | ext->driver.probe = saa7146_init_one; |
533 | ext->driver.remove = saa7146_remove_one; |
534 | |
535 | pr_info("register extension '%s'\n" , ext->name); |
536 | return pci_register_driver(&ext->driver); |
537 | } |
538 | |
539 | int saa7146_unregister_extension(struct saa7146_extension* ext) |
540 | { |
541 | DEB_EE("ext:%p\n" , ext); |
542 | pr_info("unregister extension '%s'\n" , ext->name); |
543 | pci_unregister_driver(dev: &ext->driver); |
544 | return 0; |
545 | } |
546 | |
547 | EXPORT_SYMBOL_GPL(saa7146_register_extension); |
548 | EXPORT_SYMBOL_GPL(saa7146_unregister_extension); |
549 | |
550 | /* misc functions used by extension modules */ |
551 | EXPORT_SYMBOL_GPL(saa7146_pgtable_alloc); |
552 | EXPORT_SYMBOL_GPL(saa7146_pgtable_free); |
553 | EXPORT_SYMBOL_GPL(saa7146_pgtable_build_single); |
554 | EXPORT_SYMBOL_GPL(saa7146_vmalloc_build_pgtable); |
555 | EXPORT_SYMBOL_GPL(saa7146_vfree_destroy_pgtable); |
556 | EXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done); |
557 | |
558 | EXPORT_SYMBOL_GPL(saa7146_setgpio); |
559 | |
560 | EXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare); |
561 | |
562 | EXPORT_SYMBOL_GPL(saa7146_debug); |
563 | |
564 | MODULE_AUTHOR("Michael Hunold <michael@mihu.de>" ); |
565 | MODULE_DESCRIPTION("driver for generic saa7146-based hardware" ); |
566 | MODULE_LICENSE("GPL" ); |
567 | |