.. | .. |
---|
1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
---|
2 | 2 | /* |
---|
3 | | - * Copyright (C) 2017 Intel Corporation |
---|
| 3 | + * Copyright (C) 2017,2020 Intel Corporation |
---|
4 | 4 | * |
---|
5 | 5 | * Based partially on Intel IPU4 driver written by |
---|
6 | 6 | * Sakari Ailus <sakari.ailus@linux.intel.com> |
---|
.. | .. |
---|
9 | 9 | * Jouni Ukkonen <jouni.ukkonen@intel.com> |
---|
10 | 10 | * Antti Laakso <antti.laakso@intel.com> |
---|
11 | 11 | * et al. |
---|
12 | | - * |
---|
13 | 12 | */ |
---|
14 | 13 | |
---|
15 | 14 | #include <linux/delay.h> |
---|
16 | 15 | #include <linux/interrupt.h> |
---|
| 16 | +#include <linux/iopoll.h> |
---|
17 | 17 | #include <linux/module.h> |
---|
18 | 18 | #include <linux/pci.h> |
---|
| 19 | +#include <linux/pfn.h> |
---|
19 | 20 | #include <linux/pm_runtime.h> |
---|
20 | 21 | #include <linux/property.h> |
---|
21 | 22 | #include <linux/vmalloc.h> |
---|
.. | .. |
---|
96 | 97 | static void cio2_fbpt_exit_dummy(struct cio2_device *cio2) |
---|
97 | 98 | { |
---|
98 | 99 | if (cio2->dummy_lop) { |
---|
99 | | - dma_free_coherent(&cio2->pci_dev->dev, CIO2_PAGE_SIZE, |
---|
| 100 | + dma_free_coherent(&cio2->pci_dev->dev, PAGE_SIZE, |
---|
100 | 101 | cio2->dummy_lop, cio2->dummy_lop_bus_addr); |
---|
101 | 102 | cio2->dummy_lop = NULL; |
---|
102 | 103 | } |
---|
103 | 104 | if (cio2->dummy_page) { |
---|
104 | | - dma_free_coherent(&cio2->pci_dev->dev, CIO2_PAGE_SIZE, |
---|
| 105 | + dma_free_coherent(&cio2->pci_dev->dev, PAGE_SIZE, |
---|
105 | 106 | cio2->dummy_page, cio2->dummy_page_bus_addr); |
---|
106 | 107 | cio2->dummy_page = NULL; |
---|
107 | 108 | } |
---|
.. | .. |
---|
111 | 112 | { |
---|
112 | 113 | unsigned int i; |
---|
113 | 114 | |
---|
114 | | - cio2->dummy_page = dma_alloc_coherent(&cio2->pci_dev->dev, |
---|
115 | | - CIO2_PAGE_SIZE, |
---|
| 115 | + cio2->dummy_page = dma_alloc_coherent(&cio2->pci_dev->dev, PAGE_SIZE, |
---|
116 | 116 | &cio2->dummy_page_bus_addr, |
---|
117 | 117 | GFP_KERNEL); |
---|
118 | | - cio2->dummy_lop = dma_alloc_coherent(&cio2->pci_dev->dev, |
---|
119 | | - CIO2_PAGE_SIZE, |
---|
| 118 | + cio2->dummy_lop = dma_alloc_coherent(&cio2->pci_dev->dev, PAGE_SIZE, |
---|
120 | 119 | &cio2->dummy_lop_bus_addr, |
---|
121 | 120 | GFP_KERNEL); |
---|
122 | 121 | if (!cio2->dummy_page || !cio2->dummy_lop) { |
---|
.. | .. |
---|
127 | 126 | * List of Pointers(LOP) contains 1024x32b pointers to 4KB page each |
---|
128 | 127 | * Initialize each entry to dummy_page bus base address. |
---|
129 | 128 | */ |
---|
130 | | - for (i = 0; i < CIO2_PAGE_SIZE / sizeof(*cio2->dummy_lop); i++) |
---|
131 | | - cio2->dummy_lop[i] = cio2->dummy_page_bus_addr >> PAGE_SHIFT; |
---|
| 129 | + for (i = 0; i < CIO2_LOP_ENTRIES; i++) |
---|
| 130 | + cio2->dummy_lop[i] = PFN_DOWN(cio2->dummy_page_bus_addr); |
---|
132 | 131 | |
---|
133 | 132 | return 0; |
---|
134 | 133 | } |
---|
.. | .. |
---|
160 | 159 | unsigned int i; |
---|
161 | 160 | |
---|
162 | 161 | entry[0].first_entry.first_page_offset = 0; |
---|
163 | | - entry[1].second_entry.num_of_pages = |
---|
164 | | - CIO2_PAGE_SIZE / sizeof(u32) * CIO2_MAX_LOPS; |
---|
165 | | - entry[1].second_entry.last_page_available_bytes = CIO2_PAGE_SIZE - 1; |
---|
| 162 | + entry[1].second_entry.num_of_pages = CIO2_LOP_ENTRIES * CIO2_MAX_LOPS; |
---|
| 163 | + entry[1].second_entry.last_page_available_bytes = PAGE_SIZE - 1; |
---|
166 | 164 | |
---|
167 | 165 | for (i = 0; i < CIO2_MAX_LOPS; i++) |
---|
168 | | - entry[i].lop_page_addr = cio2->dummy_lop_bus_addr >> PAGE_SHIFT; |
---|
| 166 | + entry[i].lop_page_addr = PFN_DOWN(cio2->dummy_lop_bus_addr); |
---|
169 | 167 | |
---|
170 | 168 | cio2_fbpt_entry_enable(cio2, entry); |
---|
171 | 169 | } |
---|
.. | .. |
---|
182 | 180 | |
---|
183 | 181 | entry[0].first_entry.first_page_offset = b->offset; |
---|
184 | 182 | remaining = length + entry[0].first_entry.first_page_offset; |
---|
185 | | - entry[1].second_entry.num_of_pages = |
---|
186 | | - DIV_ROUND_UP(remaining, CIO2_PAGE_SIZE); |
---|
| 183 | + entry[1].second_entry.num_of_pages = PFN_UP(remaining); |
---|
187 | 184 | /* |
---|
188 | 185 | * last_page_available_bytes has the offset of the last byte in the |
---|
189 | 186 | * last page which is still accessible by DMA. DMA cannot access |
---|
190 | 187 | * beyond this point. Valid range for this is from 0 to 4095. |
---|
191 | 188 | * 0 indicates 1st byte in the page is DMA accessible. |
---|
192 | | - * 4095 (CIO2_PAGE_SIZE - 1) means every single byte in the last page |
---|
| 189 | + * 4095 (PAGE_SIZE - 1) means every single byte in the last page |
---|
193 | 190 | * is available for DMA transfer. |
---|
194 | 191 | */ |
---|
195 | 192 | entry[1].second_entry.last_page_available_bytes = |
---|
196 | 193 | (remaining & ~PAGE_MASK) ? |
---|
197 | | - (remaining & ~PAGE_MASK) - 1 : |
---|
198 | | - CIO2_PAGE_SIZE - 1; |
---|
| 194 | + (remaining & ~PAGE_MASK) - 1 : PAGE_SIZE - 1; |
---|
199 | 195 | /* Fill FBPT */ |
---|
200 | 196 | remaining = length; |
---|
201 | 197 | i = 0; |
---|
202 | 198 | while (remaining > 0) { |
---|
203 | | - entry->lop_page_addr = b->lop_bus_addr[i] >> PAGE_SHIFT; |
---|
204 | | - remaining -= CIO2_PAGE_SIZE / sizeof(u32) * CIO2_PAGE_SIZE; |
---|
| 199 | + entry->lop_page_addr = PFN_DOWN(b->lop_bus_addr[i]); |
---|
| 200 | + remaining -= CIO2_LOP_ENTRIES * PAGE_SIZE; |
---|
205 | 201 | entry++; |
---|
206 | 202 | i++; |
---|
207 | 203 | } |
---|
.. | .. |
---|
209 | 205 | /* |
---|
210 | 206 | * The first not meaningful FBPT entry should point to a valid LOP |
---|
211 | 207 | */ |
---|
212 | | - entry->lop_page_addr = cio2->dummy_lop_bus_addr >> PAGE_SHIFT; |
---|
| 208 | + entry->lop_page_addr = PFN_DOWN(cio2->dummy_lop_bus_addr); |
---|
213 | 209 | |
---|
214 | 210 | cio2_fbpt_entry_enable(cio2, entry); |
---|
215 | 211 | } |
---|
.. | .. |
---|
222 | 218 | GFP_KERNEL); |
---|
223 | 219 | if (!q->fbpt) |
---|
224 | 220 | return -ENOMEM; |
---|
225 | | - |
---|
226 | | - memset(q->fbpt, 0, CIO2_FBPT_SIZE); |
---|
227 | 221 | |
---|
228 | 222 | return 0; |
---|
229 | 223 | } |
---|
.. | .. |
---|
266 | 260 | */ |
---|
267 | 261 | |
---|
268 | 262 | /* |
---|
269 | | - * shift for keeping value range suitable for 32-bit integer arithmetics |
---|
| 263 | + * shift for keeping value range suitable for 32-bit integer arithmetic |
---|
270 | 264 | */ |
---|
271 | 265 | #define LIMIT_SHIFT 8 |
---|
272 | 266 | |
---|
.. | .. |
---|
297 | 291 | struct cio2_csi2_timing *timing) |
---|
298 | 292 | { |
---|
299 | 293 | struct device *dev = &cio2->pci_dev->dev; |
---|
300 | | - struct v4l2_querymenu qm = {.id = V4L2_CID_LINK_FREQ, }; |
---|
| 294 | + struct v4l2_querymenu qm = { .id = V4L2_CID_LINK_FREQ }; |
---|
301 | 295 | struct v4l2_ctrl *link_freq; |
---|
302 | 296 | s64 freq; |
---|
303 | 297 | int r; |
---|
.. | .. |
---|
361 | 355 | void __iomem *const base = cio2->base; |
---|
362 | 356 | u8 lanes, csi2bus = q->csi2.port; |
---|
363 | 357 | u8 sensor_vc = SENSOR_VIR_CH_DFLT; |
---|
364 | | - struct cio2_csi2_timing timing; |
---|
| 358 | + struct cio2_csi2_timing timing = { 0 }; |
---|
365 | 359 | int i, r; |
---|
366 | 360 | |
---|
367 | 361 | fmt = cio2_find_format(NULL, &q->subdev_fmt.code); |
---|
.. | .. |
---|
477 | 471 | } |
---|
478 | 472 | |
---|
479 | 473 | /* Enable DMA */ |
---|
480 | | - writel(q->fbpt_bus_addr >> PAGE_SHIFT, |
---|
481 | | - base + CIO2_REG_CDMABA(CIO2_DMA_CHAN)); |
---|
| 474 | + writel(PFN_DOWN(q->fbpt_bus_addr), base + CIO2_REG_CDMABA(CIO2_DMA_CHAN)); |
---|
482 | 475 | |
---|
483 | 476 | writel(num_buffers1 << CIO2_CDMAC0_FBPT_LEN_SHIFT | |
---|
484 | 477 | FBPT_WIDTH << CIO2_CDMAC0_FBPT_WIDTH_SHIFT | |
---|
.. | .. |
---|
514 | 507 | |
---|
515 | 508 | static void cio2_hw_exit(struct cio2_device *cio2, struct cio2_queue *q) |
---|
516 | 509 | { |
---|
517 | | - void __iomem *base = cio2->base; |
---|
518 | | - unsigned int i, maxloops = 1000; |
---|
| 510 | + void __iomem *const base = cio2->base; |
---|
| 511 | + unsigned int i; |
---|
| 512 | + u32 value; |
---|
| 513 | + int ret; |
---|
519 | 514 | |
---|
520 | 515 | /* Disable CSI receiver and MIPI backend devices */ |
---|
521 | 516 | writel(0, q->csi_rx_base + CIO2_REG_IRQCTRL_MASK); |
---|
.. | .. |
---|
525 | 520 | |
---|
526 | 521 | /* Halt DMA */ |
---|
527 | 522 | writel(0, base + CIO2_REG_CDMAC0(CIO2_DMA_CHAN)); |
---|
528 | | - do { |
---|
529 | | - if (readl(base + CIO2_REG_CDMAC0(CIO2_DMA_CHAN)) & |
---|
530 | | - CIO2_CDMAC0_DMA_HALTED) |
---|
531 | | - break; |
---|
532 | | - usleep_range(1000, 2000); |
---|
533 | | - } while (--maxloops); |
---|
534 | | - if (!maxloops) |
---|
| 523 | + ret = readl_poll_timeout(base + CIO2_REG_CDMAC0(CIO2_DMA_CHAN), |
---|
| 524 | + value, value & CIO2_CDMAC0_DMA_HALTED, |
---|
| 525 | + 4000, 2000000); |
---|
| 526 | + if (ret) |
---|
535 | 527 | dev_err(&cio2->pci_dev->dev, |
---|
536 | 528 | "DMA %i can not be halted\n", CIO2_DMA_CHAN); |
---|
537 | 529 | |
---|
.. | .. |
---|
547 | 539 | { |
---|
548 | 540 | struct device *dev = &cio2->pci_dev->dev; |
---|
549 | 541 | struct cio2_queue *q = cio2->cur_queue; |
---|
550 | | - int buffers_found = 0; |
---|
| 542 | + struct cio2_fbpt_entry *entry; |
---|
551 | 543 | u64 ns = ktime_get_ns(); |
---|
552 | 544 | |
---|
553 | 545 | if (dma_chan >= CIO2_QUEUES) { |
---|
.. | .. |
---|
555 | 547 | return; |
---|
556 | 548 | } |
---|
557 | 549 | |
---|
| 550 | + entry = &q->fbpt[q->bufs_first * CIO2_MAX_LOPS]; |
---|
| 551 | + if (entry->first_entry.ctrl & CIO2_FBPT_CTRL_VALID) { |
---|
| 552 | + dev_warn(&cio2->pci_dev->dev, |
---|
| 553 | + "no ready buffers found on DMA channel %u\n", |
---|
| 554 | + dma_chan); |
---|
| 555 | + return; |
---|
| 556 | + } |
---|
| 557 | + |
---|
558 | 558 | /* Find out which buffer(s) are ready */ |
---|
559 | 559 | do { |
---|
560 | | - struct cio2_fbpt_entry *const entry = |
---|
561 | | - &q->fbpt[q->bufs_first * CIO2_MAX_LOPS]; |
---|
562 | 560 | struct cio2_buffer *b; |
---|
563 | | - |
---|
564 | | - if (entry->first_entry.ctrl & CIO2_FBPT_CTRL_VALID) |
---|
565 | | - break; |
---|
566 | 561 | |
---|
567 | 562 | b = q->bufs[q->bufs_first]; |
---|
568 | 563 | if (b) { |
---|
.. | .. |
---|
585 | 580 | atomic_inc(&q->frame_sequence); |
---|
586 | 581 | cio2_fbpt_entry_init_dummy(cio2, entry); |
---|
587 | 582 | q->bufs_first = (q->bufs_first + 1) % CIO2_MAX_BUFFERS; |
---|
588 | | - buffers_found++; |
---|
589 | | - } while (1); |
---|
590 | | - |
---|
591 | | - if (buffers_found == 0) |
---|
592 | | - dev_warn(&cio2->pci_dev->dev, |
---|
593 | | - "no ready buffers found on DMA channel %u\n", |
---|
594 | | - dma_chan); |
---|
| 583 | + entry = &q->fbpt[q->bufs_first * CIO2_MAX_LOPS]; |
---|
| 584 | + } while (!(entry->first_entry.ctrl & CIO2_FBPT_CTRL_VALID)); |
---|
595 | 585 | } |
---|
596 | 586 | |
---|
597 | 587 | static void cio2_queue_event_sof(struct cio2_device *cio2, struct cio2_queue *q) |
---|
.. | .. |
---|
844 | 834 | struct device *dev = &cio2->pci_dev->dev; |
---|
845 | 835 | struct cio2_buffer *b = |
---|
846 | 836 | container_of(vb, struct cio2_buffer, vbb.vb2_buf); |
---|
847 | | - static const unsigned int entries_per_page = |
---|
848 | | - CIO2_PAGE_SIZE / sizeof(u32); |
---|
849 | | - unsigned int pages = DIV_ROUND_UP(vb->planes[0].length, CIO2_PAGE_SIZE); |
---|
850 | | - unsigned int lops = DIV_ROUND_UP(pages + 1, entries_per_page); |
---|
| 837 | + unsigned int pages = PFN_UP(vb->planes[0].length); |
---|
| 838 | + unsigned int lops = DIV_ROUND_UP(pages + 1, CIO2_LOP_ENTRIES); |
---|
851 | 839 | struct sg_table *sg; |
---|
852 | | - struct sg_page_iter sg_iter; |
---|
853 | | - int i, j; |
---|
| 840 | + struct sg_dma_page_iter sg_iter; |
---|
| 841 | + unsigned int i, j; |
---|
854 | 842 | |
---|
855 | 843 | if (lops <= 0 || lops > CIO2_MAX_LOPS) { |
---|
856 | 844 | dev_err(dev, "%s: bad buffer size (%i)\n", __func__, |
---|
.. | .. |
---|
861 | 849 | memset(b->lop, 0, sizeof(b->lop)); |
---|
862 | 850 | /* Allocate LOP table */ |
---|
863 | 851 | for (i = 0; i < lops; i++) { |
---|
864 | | - b->lop[i] = dma_alloc_coherent(dev, CIO2_PAGE_SIZE, |
---|
| 852 | + b->lop[i] = dma_alloc_coherent(dev, PAGE_SIZE, |
---|
865 | 853 | &b->lop_bus_addr[i], GFP_KERNEL); |
---|
866 | 854 | if (!b->lop[i]) |
---|
867 | 855 | goto fail; |
---|
.. | .. |
---|
876 | 864 | b->offset = sg->sgl->offset; |
---|
877 | 865 | |
---|
878 | 866 | i = j = 0; |
---|
879 | | - for_each_sg_page(sg->sgl, &sg_iter, sg->nents, 0) { |
---|
| 867 | + for_each_sg_dma_page(sg->sgl, &sg_iter, sg->nents, 0) { |
---|
880 | 868 | if (!pages--) |
---|
881 | 869 | break; |
---|
882 | | - b->lop[i][j] = sg_page_iter_dma_address(&sg_iter) >> PAGE_SHIFT; |
---|
| 870 | + b->lop[i][j] = PFN_DOWN(sg_page_iter_dma_address(&sg_iter)); |
---|
883 | 871 | j++; |
---|
884 | | - if (j == entries_per_page) { |
---|
| 872 | + if (j == CIO2_LOP_ENTRIES) { |
---|
885 | 873 | i++; |
---|
886 | 874 | j = 0; |
---|
887 | 875 | } |
---|
888 | 876 | } |
---|
889 | 877 | |
---|
890 | | - b->lop[i][j] = cio2->dummy_page_bus_addr >> PAGE_SHIFT; |
---|
| 878 | + b->lop[i][j] = PFN_DOWN(cio2->dummy_page_bus_addr); |
---|
891 | 879 | return 0; |
---|
892 | 880 | fail: |
---|
893 | | - for (i--; i >= 0; i--) |
---|
894 | | - dma_free_coherent(dev, CIO2_PAGE_SIZE, |
---|
895 | | - b->lop[i], b->lop_bus_addr[i]); |
---|
| 881 | + while (i--) |
---|
| 882 | + dma_free_coherent(dev, PAGE_SIZE, b->lop[i], b->lop_bus_addr[i]); |
---|
896 | 883 | return -ENOMEM; |
---|
897 | 884 | } |
---|
898 | 885 | |
---|
.. | .. |
---|
982 | 969 | /* Free LOP table */ |
---|
983 | 970 | for (i = 0; i < CIO2_MAX_LOPS; i++) { |
---|
984 | 971 | if (b->lop[i]) |
---|
985 | | - dma_free_coherent(&cio2->pci_dev->dev, CIO2_PAGE_SIZE, |
---|
| 972 | + dma_free_coherent(&cio2->pci_dev->dev, PAGE_SIZE, |
---|
986 | 973 | b->lop[i], b->lop_bus_addr[i]); |
---|
987 | 974 | } |
---|
988 | 975 | } |
---|
.. | .. |
---|
1067 | 1054 | { |
---|
1068 | 1055 | struct cio2_device *cio2 = video_drvdata(file); |
---|
1069 | 1056 | |
---|
1070 | | - strlcpy(cap->driver, CIO2_NAME, sizeof(cap->driver)); |
---|
1071 | | - strlcpy(cap->card, CIO2_DEVICE_NAME, sizeof(cap->card)); |
---|
| 1057 | + strscpy(cap->driver, CIO2_NAME, sizeof(cap->driver)); |
---|
| 1058 | + strscpy(cap->card, CIO2_DEVICE_NAME, sizeof(cap->card)); |
---|
1072 | 1059 | snprintf(cap->bus_info, sizeof(cap->bus_info), |
---|
1073 | 1060 | "PCI:%s", pci_name(cio2->pci_dev)); |
---|
1074 | 1061 | |
---|
.. | .. |
---|
1146 | 1133 | if (input->index > 0) |
---|
1147 | 1134 | return -EINVAL; |
---|
1148 | 1135 | |
---|
1149 | | - strlcpy(input->name, "camera", sizeof(input->name)); |
---|
| 1136 | + strscpy(input->name, "camera", sizeof(input->name)); |
---|
1150 | 1137 | input->type = V4L2_INPUT_TYPE_CAMERA; |
---|
1151 | 1138 | |
---|
1152 | 1139 | return 0; |
---|
.. | .. |
---|
1177 | 1164 | |
---|
1178 | 1165 | static const struct v4l2_ioctl_ops cio2_v4l2_ioctl_ops = { |
---|
1179 | 1166 | .vidioc_querycap = cio2_v4l2_querycap, |
---|
1180 | | - .vidioc_enum_fmt_vid_cap_mplane = cio2_v4l2_enum_fmt, |
---|
| 1167 | + .vidioc_enum_fmt_vid_cap = cio2_v4l2_enum_fmt, |
---|
1181 | 1168 | .vidioc_g_fmt_vid_cap_mplane = cio2_v4l2_g_fmt, |
---|
1182 | 1169 | .vidioc_s_fmt_vid_cap_mplane = cio2_v4l2_s_fmt, |
---|
1183 | 1170 | .vidioc_try_fmt_vid_cap_mplane = cio2_v4l2_try_fmt, |
---|
.. | .. |
---|
1438 | 1425 | struct cio2_device *cio2 = container_of(notifier, struct cio2_device, |
---|
1439 | 1426 | notifier); |
---|
1440 | 1427 | struct sensor_async_subdev *s_asd; |
---|
| 1428 | + struct v4l2_async_subdev *asd; |
---|
1441 | 1429 | struct cio2_queue *q; |
---|
1442 | | - unsigned int i, pad; |
---|
| 1430 | + unsigned int pad; |
---|
1443 | 1431 | int ret; |
---|
1444 | 1432 | |
---|
1445 | | - for (i = 0; i < notifier->num_subdevs; i++) { |
---|
1446 | | - s_asd = container_of(cio2->notifier.subdevs[i], |
---|
1447 | | - struct sensor_async_subdev, asd); |
---|
| 1433 | + list_for_each_entry(asd, &cio2->notifier.asd_list, asd_list) { |
---|
| 1434 | + s_asd = container_of(asd, struct sensor_async_subdev, asd); |
---|
1448 | 1435 | q = &cio2->queue[s_asd->csi2.port]; |
---|
1449 | 1436 | |
---|
1450 | 1437 | for (pad = 0; pad < q->sensor->entity.num_pads; pad++) |
---|
.. | .. |
---|
1466 | 1453 | if (ret) { |
---|
1467 | 1454 | dev_err(&cio2->pci_dev->dev, |
---|
1468 | 1455 | "failed to create link for %s\n", |
---|
1469 | | - cio2->queue[i].sensor->name); |
---|
| 1456 | + q->sensor->name); |
---|
1470 | 1457 | return ret; |
---|
1471 | 1458 | } |
---|
1472 | 1459 | } |
---|
.. | .. |
---|
1480 | 1467 | .complete = cio2_notifier_complete, |
---|
1481 | 1468 | }; |
---|
1482 | 1469 | |
---|
1483 | | -static int cio2_fwnode_parse(struct device *dev, |
---|
1484 | | - struct v4l2_fwnode_endpoint *vep, |
---|
1485 | | - struct v4l2_async_subdev *asd) |
---|
| 1470 | +static int cio2_parse_firmware(struct cio2_device *cio2) |
---|
1486 | 1471 | { |
---|
1487 | | - struct sensor_async_subdev *s_asd = |
---|
1488 | | - container_of(asd, struct sensor_async_subdev, asd); |
---|
1489 | | - |
---|
1490 | | - if (vep->bus_type != V4L2_MBUS_CSI2) { |
---|
1491 | | - dev_err(dev, "Only CSI2 bus type is currently supported\n"); |
---|
1492 | | - return -EINVAL; |
---|
1493 | | - } |
---|
1494 | | - |
---|
1495 | | - s_asd->csi2.port = vep->base.port; |
---|
1496 | | - s_asd->csi2.lanes = vep->bus.mipi_csi2.num_data_lanes; |
---|
1497 | | - |
---|
1498 | | - return 0; |
---|
1499 | | -} |
---|
1500 | | - |
---|
1501 | | -static int cio2_notifier_init(struct cio2_device *cio2) |
---|
1502 | | -{ |
---|
| 1472 | + unsigned int i; |
---|
1503 | 1473 | int ret; |
---|
1504 | 1474 | |
---|
1505 | | - ret = v4l2_async_notifier_parse_fwnode_endpoints( |
---|
1506 | | - &cio2->pci_dev->dev, &cio2->notifier, |
---|
1507 | | - sizeof(struct sensor_async_subdev), |
---|
1508 | | - cio2_fwnode_parse); |
---|
1509 | | - if (ret < 0) |
---|
| 1475 | + for (i = 0; i < CIO2_NUM_PORTS; i++) { |
---|
| 1476 | + struct v4l2_fwnode_endpoint vep = { |
---|
| 1477 | + .bus_type = V4L2_MBUS_CSI2_DPHY |
---|
| 1478 | + }; |
---|
| 1479 | + struct sensor_async_subdev *s_asd; |
---|
| 1480 | + struct v4l2_async_subdev *asd; |
---|
| 1481 | + struct fwnode_handle *ep; |
---|
| 1482 | + |
---|
| 1483 | + ep = fwnode_graph_get_endpoint_by_id( |
---|
| 1484 | + dev_fwnode(&cio2->pci_dev->dev), i, 0, |
---|
| 1485 | + FWNODE_GRAPH_ENDPOINT_NEXT); |
---|
| 1486 | + |
---|
| 1487 | + if (!ep) |
---|
| 1488 | + continue; |
---|
| 1489 | + |
---|
| 1490 | + ret = v4l2_fwnode_endpoint_parse(ep, &vep); |
---|
| 1491 | + if (ret) |
---|
| 1492 | + goto err_parse; |
---|
| 1493 | + |
---|
| 1494 | + asd = v4l2_async_notifier_add_fwnode_remote_subdev( |
---|
| 1495 | + &cio2->notifier, ep, sizeof(*s_asd)); |
---|
| 1496 | + if (IS_ERR(asd)) { |
---|
| 1497 | + ret = PTR_ERR(asd); |
---|
| 1498 | + goto err_parse; |
---|
| 1499 | + } |
---|
| 1500 | + |
---|
| 1501 | + s_asd = container_of(asd, struct sensor_async_subdev, asd); |
---|
| 1502 | + s_asd->csi2.port = vep.base.port; |
---|
| 1503 | + s_asd->csi2.lanes = vep.bus.mipi_csi2.num_data_lanes; |
---|
| 1504 | + |
---|
| 1505 | + fwnode_handle_put(ep); |
---|
| 1506 | + |
---|
| 1507 | + continue; |
---|
| 1508 | + |
---|
| 1509 | +err_parse: |
---|
| 1510 | + fwnode_handle_put(ep); |
---|
1510 | 1511 | return ret; |
---|
1511 | | - |
---|
1512 | | - if (!cio2->notifier.num_subdevs) |
---|
1513 | | - return -ENODEV; /* no endpoint */ |
---|
1514 | | - |
---|
1515 | | - cio2->notifier.ops = &cio2_async_ops; |
---|
1516 | | - ret = v4l2_async_notifier_register(&cio2->v4l2_dev, &cio2->notifier); |
---|
1517 | | - if (ret) { |
---|
1518 | | - dev_err(&cio2->pci_dev->dev, |
---|
1519 | | - "failed to register async notifier : %d\n", ret); |
---|
1520 | | - v4l2_async_notifier_cleanup(&cio2->notifier); |
---|
1521 | 1512 | } |
---|
1522 | 1513 | |
---|
1523 | | - return ret; |
---|
1524 | | -} |
---|
| 1514 | + /* |
---|
| 1515 | + * Proceed even without sensors connected to allow the device to |
---|
| 1516 | + * suspend. |
---|
| 1517 | + */ |
---|
| 1518 | + cio2->notifier.ops = &cio2_async_ops; |
---|
| 1519 | + ret = v4l2_async_notifier_register(&cio2->v4l2_dev, &cio2->notifier); |
---|
| 1520 | + if (ret) |
---|
| 1521 | + dev_err(&cio2->pci_dev->dev, |
---|
| 1522 | + "failed to register async notifier : %d\n", ret); |
---|
1525 | 1523 | |
---|
1526 | | -static void cio2_notifier_exit(struct cio2_device *cio2) |
---|
1527 | | -{ |
---|
1528 | | - v4l2_async_notifier_unregister(&cio2->notifier); |
---|
1529 | | - v4l2_async_notifier_cleanup(&cio2->notifier); |
---|
| 1524 | + return ret; |
---|
1530 | 1525 | } |
---|
1531 | 1526 | |
---|
1532 | 1527 | /**************** Queue initialization ****************/ |
---|
.. | .. |
---|
1605 | 1600 | subdev->owner = THIS_MODULE; |
---|
1606 | 1601 | snprintf(subdev->name, sizeof(subdev->name), |
---|
1607 | 1602 | CIO2_ENTITY_NAME " %td", q - cio2->queue); |
---|
| 1603 | + subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; |
---|
1608 | 1604 | v4l2_set_subdevdata(subdev, cio2); |
---|
1609 | 1605 | r = v4l2_device_register_subdev(&cio2->v4l2_dev, subdev); |
---|
1610 | 1606 | if (r) { |
---|
.. | .. |
---|
1627 | 1623 | if (r) { |
---|
1628 | 1624 | dev_err(&cio2->pci_dev->dev, |
---|
1629 | 1625 | "failed to initialize videobuf2 queue (%d)\n", r); |
---|
1630 | | - goto fail_vbq; |
---|
| 1626 | + goto fail_subdev; |
---|
1631 | 1627 | } |
---|
1632 | 1628 | |
---|
1633 | 1629 | /* Initialize vdev */ |
---|
.. | .. |
---|
1641 | 1637 | vdev->queue = &q->vbq; |
---|
1642 | 1638 | vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING; |
---|
1643 | 1639 | video_set_drvdata(vdev, cio2); |
---|
1644 | | - r = video_register_device(vdev, VFL_TYPE_GRABBER, -1); |
---|
| 1640 | + r = video_register_device(vdev, VFL_TYPE_VIDEO, -1); |
---|
1645 | 1641 | if (r) { |
---|
1646 | 1642 | dev_err(&cio2->pci_dev->dev, |
---|
1647 | 1643 | "failed to register video device (%d)\n", r); |
---|
.. | .. |
---|
1658 | 1654 | return 0; |
---|
1659 | 1655 | |
---|
1660 | 1656 | fail_link: |
---|
1661 | | - video_unregister_device(&q->vdev); |
---|
| 1657 | + vb2_video_unregister_device(&q->vdev); |
---|
1662 | 1658 | fail_vdev: |
---|
1663 | | - vb2_queue_release(vbq); |
---|
1664 | | -fail_vbq: |
---|
1665 | 1659 | v4l2_device_unregister_subdev(subdev); |
---|
1666 | 1660 | fail_subdev: |
---|
1667 | 1661 | media_entity_cleanup(&vdev->entity); |
---|
.. | .. |
---|
1678 | 1672 | |
---|
1679 | 1673 | static void cio2_queue_exit(struct cio2_device *cio2, struct cio2_queue *q) |
---|
1680 | 1674 | { |
---|
1681 | | - video_unregister_device(&q->vdev); |
---|
| 1675 | + vb2_video_unregister_device(&q->vdev); |
---|
1682 | 1676 | media_entity_cleanup(&q->vdev.entity); |
---|
1683 | | - vb2_queue_release(&q->vbq); |
---|
1684 | 1677 | v4l2_device_unregister_subdev(&q->subdev); |
---|
1685 | 1678 | media_entity_cleanup(&q->subdev.entity); |
---|
1686 | 1679 | cio2_fbpt_exit(q, &cio2->pci_dev->dev); |
---|
.. | .. |
---|
1717 | 1710 | |
---|
1718 | 1711 | /**************** PCI interface ****************/ |
---|
1719 | 1712 | |
---|
1720 | | -static int cio2_pci_config_setup(struct pci_dev *dev) |
---|
1721 | | -{ |
---|
1722 | | - u16 pci_command; |
---|
1723 | | - int r = pci_enable_msi(dev); |
---|
1724 | | - |
---|
1725 | | - if (r) { |
---|
1726 | | - dev_err(&dev->dev, "failed to enable MSI (%d)\n", r); |
---|
1727 | | - return r; |
---|
1728 | | - } |
---|
1729 | | - |
---|
1730 | | - pci_read_config_word(dev, PCI_COMMAND, &pci_command); |
---|
1731 | | - pci_command |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | |
---|
1732 | | - PCI_COMMAND_INTX_DISABLE; |
---|
1733 | | - pci_write_config_word(dev, PCI_COMMAND, pci_command); |
---|
1734 | | - |
---|
1735 | | - return 0; |
---|
1736 | | -} |
---|
1737 | | - |
---|
1738 | 1713 | static int cio2_pci_probe(struct pci_dev *pci_dev, |
---|
1739 | 1714 | const struct pci_device_id *id) |
---|
1740 | 1715 | { |
---|
1741 | 1716 | struct cio2_device *cio2; |
---|
1742 | | - void __iomem *const *iomap; |
---|
1743 | 1717 | int r; |
---|
1744 | 1718 | |
---|
1745 | 1719 | cio2 = devm_kzalloc(&pci_dev->dev, sizeof(*cio2), GFP_KERNEL); |
---|
.. | .. |
---|
1762 | 1736 | return -ENODEV; |
---|
1763 | 1737 | } |
---|
1764 | 1738 | |
---|
1765 | | - iomap = pcim_iomap_table(pci_dev); |
---|
1766 | | - if (!iomap) { |
---|
1767 | | - dev_err(&pci_dev->dev, "failed to iomap table\n"); |
---|
1768 | | - return -ENODEV; |
---|
1769 | | - } |
---|
1770 | | - |
---|
1771 | | - cio2->base = iomap[CIO2_PCI_BAR]; |
---|
| 1739 | + cio2->base = pcim_iomap_table(pci_dev)[CIO2_PCI_BAR]; |
---|
1772 | 1740 | |
---|
1773 | 1741 | pci_set_drvdata(pci_dev, cio2); |
---|
1774 | 1742 | |
---|
.. | .. |
---|
1780 | 1748 | return -ENODEV; |
---|
1781 | 1749 | } |
---|
1782 | 1750 | |
---|
1783 | | - r = cio2_pci_config_setup(pci_dev); |
---|
1784 | | - if (r) |
---|
1785 | | - return -ENODEV; |
---|
| 1751 | + r = pci_enable_msi(pci_dev); |
---|
| 1752 | + if (r) { |
---|
| 1753 | + dev_err(&pci_dev->dev, "failed to enable MSI (%d)\n", r); |
---|
| 1754 | + return r; |
---|
| 1755 | + } |
---|
1786 | 1756 | |
---|
1787 | 1757 | r = cio2_fbpt_init_dummy(cio2); |
---|
1788 | 1758 | if (r) |
---|
.. | .. |
---|
1791 | 1761 | mutex_init(&cio2->lock); |
---|
1792 | 1762 | |
---|
1793 | 1763 | cio2->media_dev.dev = &cio2->pci_dev->dev; |
---|
1794 | | - strlcpy(cio2->media_dev.model, CIO2_DEVICE_NAME, |
---|
| 1764 | + strscpy(cio2->media_dev.model, CIO2_DEVICE_NAME, |
---|
1795 | 1765 | sizeof(cio2->media_dev.model)); |
---|
1796 | 1766 | snprintf(cio2->media_dev.bus_info, sizeof(cio2->media_dev.bus_info), |
---|
1797 | 1767 | "PCI:%s", pci_name(cio2->pci_dev)); |
---|
.. | .. |
---|
1814 | 1784 | if (r) |
---|
1815 | 1785 | goto fail_v4l2_device_unregister; |
---|
1816 | 1786 | |
---|
| 1787 | + v4l2_async_notifier_init(&cio2->notifier); |
---|
| 1788 | + |
---|
1817 | 1789 | /* Register notifier for subdevices we care */ |
---|
1818 | | - r = cio2_notifier_init(cio2); |
---|
| 1790 | + r = cio2_parse_firmware(cio2); |
---|
1819 | 1791 | if (r) |
---|
1820 | | - goto fail_cio2_queue_exit; |
---|
| 1792 | + goto fail_clean_notifier; |
---|
1821 | 1793 | |
---|
1822 | 1794 | r = devm_request_irq(&pci_dev->dev, pci_dev->irq, cio2_irq, |
---|
1823 | 1795 | IRQF_SHARED, CIO2_NAME, cio2); |
---|
1824 | 1796 | if (r) { |
---|
1825 | 1797 | dev_err(&pci_dev->dev, "failed to request IRQ (%d)\n", r); |
---|
1826 | | - goto fail; |
---|
| 1798 | + goto fail_clean_notifier; |
---|
1827 | 1799 | } |
---|
1828 | 1800 | |
---|
1829 | 1801 | pm_runtime_put_noidle(&pci_dev->dev); |
---|
.. | .. |
---|
1831 | 1803 | |
---|
1832 | 1804 | return 0; |
---|
1833 | 1805 | |
---|
1834 | | -fail: |
---|
1835 | | - cio2_notifier_exit(cio2); |
---|
1836 | | -fail_cio2_queue_exit: |
---|
| 1806 | +fail_clean_notifier: |
---|
| 1807 | + v4l2_async_notifier_unregister(&cio2->notifier); |
---|
| 1808 | + v4l2_async_notifier_cleanup(&cio2->notifier); |
---|
1837 | 1809 | cio2_queues_exit(cio2); |
---|
1838 | 1810 | fail_v4l2_device_unregister: |
---|
1839 | 1811 | v4l2_device_unregister(&cio2->v4l2_dev); |
---|
.. | .. |
---|
1850 | 1822 | static void cio2_pci_remove(struct pci_dev *pci_dev) |
---|
1851 | 1823 | { |
---|
1852 | 1824 | struct cio2_device *cio2 = pci_get_drvdata(pci_dev); |
---|
1853 | | - unsigned int i; |
---|
1854 | 1825 | |
---|
1855 | 1826 | media_device_unregister(&cio2->media_dev); |
---|
1856 | | - cio2_notifier_exit(cio2); |
---|
1857 | | - for (i = 0; i < CIO2_QUEUES; i++) |
---|
1858 | | - cio2_queue_exit(cio2, &cio2->queue[i]); |
---|
| 1827 | + v4l2_async_notifier_unregister(&cio2->notifier); |
---|
| 1828 | + v4l2_async_notifier_cleanup(&cio2->notifier); |
---|
| 1829 | + cio2_queues_exit(cio2); |
---|
1859 | 1830 | cio2_fbpt_exit_dummy(cio2); |
---|
1860 | 1831 | v4l2_device_unregister(&cio2->v4l2_dev); |
---|
1861 | 1832 | media_device_cleanup(&cio2->media_dev); |
---|
1862 | 1833 | mutex_destroy(&cio2->lock); |
---|
| 1834 | + |
---|
| 1835 | + pm_runtime_forbid(&pci_dev->dev); |
---|
| 1836 | + pm_runtime_get_noresume(&pci_dev->dev); |
---|
1863 | 1837 | } |
---|
1864 | 1838 | |
---|
1865 | 1839 | static int __maybe_unused cio2_runtime_suspend(struct device *dev) |
---|
.. | .. |
---|
2006 | 1980 | |
---|
2007 | 1981 | static int __maybe_unused cio2_resume(struct device *dev) |
---|
2008 | 1982 | { |
---|
2009 | | - struct pci_dev *pci_dev = to_pci_dev(dev); |
---|
2010 | | - struct cio2_device *cio2 = pci_get_drvdata(pci_dev); |
---|
2011 | | - int r = 0; |
---|
| 1983 | + struct cio2_device *cio2 = dev_get_drvdata(dev); |
---|
2012 | 1984 | struct cio2_queue *q = cio2->cur_queue; |
---|
| 1985 | + int r; |
---|
2013 | 1986 | |
---|
2014 | 1987 | dev_dbg(dev, "cio2 resume\n"); |
---|
2015 | 1988 | if (!cio2->streaming) |
---|
.. | .. |
---|
2036 | 2009 | |
---|
2037 | 2010 | static const struct pci_device_id cio2_pci_id_table[] = { |
---|
2038 | 2011 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, CIO2_PCI_ID) }, |
---|
2039 | | - { 0 } |
---|
| 2012 | + { } |
---|
2040 | 2013 | }; |
---|
2041 | 2014 | |
---|
2042 | 2015 | MODULE_DEVICE_TABLE(pci, cio2_pci_id_table); |
---|
.. | .. |
---|
2055 | 2028 | |
---|
2056 | 2029 | MODULE_AUTHOR("Tuukka Toivonen <tuukka.toivonen@intel.com>"); |
---|
2057 | 2030 | MODULE_AUTHOR("Tianshu Qiu <tian.shu.qiu@intel.com>"); |
---|
2058 | | -MODULE_AUTHOR("Jian Xu Zheng <jian.xu.zheng@intel.com>"); |
---|
| 2031 | +MODULE_AUTHOR("Jian Xu Zheng"); |
---|
2059 | 2032 | MODULE_AUTHOR("Yuning Pu <yuning.pu@intel.com>"); |
---|
2060 | 2033 | MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>"); |
---|
2061 | 2034 | MODULE_LICENSE("GPL v2"); |
---|