aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/pci/cobalt/cobalt-driver.c
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2015-05-12 07:52:21 -0400
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>2015-05-20 12:44:01 -0400
commit85756a069c55e0315ac5990806899cfb607b987f (patch)
tree47357dd6bc1a00f843afa14c86eca18b13189383 /drivers/media/pci/cobalt/cobalt-driver.c
parent48519838cc915d1af7083662471d2eb939a024c9 (diff)
[media] cobalt: add new driver
The cobalt device is a PCIe card with 4 HDMI inputs (adv7604) and a connector that can be used to hook up an adv7511 transmitter or an adv7842 receiver daughterboard. This device is used within Cisco but is sadly not available outside of Cisco. Nevertheless it is a very interesting driver that can serve as an example of how to support HDMI hardware and how to use the popular adv devices. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Diffstat (limited to 'drivers/media/pci/cobalt/cobalt-driver.c')
-rw-r--r--drivers/media/pci/cobalt/cobalt-driver.c821
1 files changed, 821 insertions, 0 deletions
diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c
new file mode 100644
index 000000000000..0f2549ab4c2b
--- /dev/null
+++ b/drivers/media/pci/cobalt/cobalt-driver.c
@@ -0,0 +1,821 @@
1/*
2 * cobalt driver initialization and card probing
3 *
4 * Derived from cx18-driver.c
5 *
6 * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
7 * All rights reserved.
8 *
9 * This program is free software; you may redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
17 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
18 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23#include <linux/delay.h>
24#include <media/adv7604.h>
25#include <media/adv7842.h>
26#include <media/adv7511.h>
27#include <media/v4l2-event.h>
28#include <media/v4l2-ctrls.h>
29
30#include "cobalt-driver.h"
31#include "cobalt-irq.h"
32#include "cobalt-i2c.h"
33#include "cobalt-v4l2.h"
34#include "cobalt-flash.h"
35#include "cobalt-alsa.h"
36#include "cobalt-omnitek.h"
37
38/* add your revision and whatnot here */
39static struct pci_device_id cobalt_pci_tbl[] = {
40 {PCI_VENDOR_ID_CISCO, PCI_DEVICE_ID_COBALT,
41 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
42 {0,}
43};
44
45MODULE_DEVICE_TABLE(pci, cobalt_pci_tbl);
46
47static atomic_t cobalt_instance = ATOMIC_INIT(0);
48
49int cobalt_debug;
50module_param_named(debug, cobalt_debug, int, 0644);
51MODULE_PARM_DESC(debug, "Debug level. Default: 0\n");
52
53int cobalt_ignore_err;
54module_param_named(ignore_err, cobalt_ignore_err, int, 0644);
55MODULE_PARM_DESC(ignore_err,
56 "If set then ignore missing i2c adapters/receivers. Default: 0\n");
57
58MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com> & Morten Hestnes");
59MODULE_DESCRIPTION("cobalt driver");
60MODULE_LICENSE("GPL");
61
62static u8 edid[256] = {
63 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
64 0x50, 0x21, 0x9C, 0x27, 0x00, 0x00, 0x00, 0x00,
65 0x19, 0x12, 0x01, 0x03, 0x80, 0x00, 0x00, 0x78,
66 0x0E, 0x00, 0xB2, 0xA0, 0x57, 0x49, 0x9B, 0x26,
67 0x10, 0x48, 0x4F, 0x2F, 0xCF, 0x00, 0x31, 0x59,
68 0x45, 0x59, 0x61, 0x59, 0x81, 0x99, 0x01, 0x01,
69 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3A,
70 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C,
71 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E,
72 0x00, 0x00, 0x00, 0xFD, 0x00, 0x31, 0x55, 0x18,
73 0x5E, 0x11, 0x00, 0x0A, 0x20, 0x20, 0x20, 0x20,
74 0x20, 0x20, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x43,
75 0x20, 0x39, 0x30, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
76 0x0A, 0x0A, 0x0A, 0x0A, 0x00, 0x00, 0x00, 0x10,
77 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x68,
79 0x02, 0x03, 0x1a, 0xc0, 0x48, 0xa2, 0x10, 0x04,
80 0x02, 0x01, 0x21, 0x14, 0x13, 0x23, 0x09, 0x07,
81 0x07, 0x65, 0x03, 0x0c, 0x00, 0x10, 0x00, 0xe2,
82 0x00, 0x2a, 0x01, 0x1d, 0x00, 0x80, 0x51, 0xd0,
83 0x1c, 0x20, 0x40, 0x80, 0x35, 0x00, 0x00, 0x00,
84 0x00, 0x00, 0x00, 0x1e, 0x8c, 0x0a, 0xd0, 0x8a,
85 0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00,
86 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
87 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
88 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
89 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
90 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
91 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
93 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
94 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd7
95};
96
97static void cobalt_set_interrupt(struct cobalt *cobalt, bool enable)
98{
99 if (enable) {
100 unsigned irqs = COBALT_SYSSTAT_VI0_INT1_MSK |
101 COBALT_SYSSTAT_VI1_INT1_MSK |
102 COBALT_SYSSTAT_VI2_INT1_MSK |
103 COBALT_SYSSTAT_VI3_INT1_MSK |
104 COBALT_SYSSTAT_VI0_INT2_MSK |
105 COBALT_SYSSTAT_VI1_INT2_MSK |
106 COBALT_SYSSTAT_VI2_INT2_MSK |
107 COBALT_SYSSTAT_VI3_INT2_MSK |
108 COBALT_SYSSTAT_VI0_LOST_DATA_MSK |
109 COBALT_SYSSTAT_VI1_LOST_DATA_MSK |
110 COBALT_SYSSTAT_VI2_LOST_DATA_MSK |
111 COBALT_SYSSTAT_VI3_LOST_DATA_MSK |
112 COBALT_SYSSTAT_AUD_IN_LOST_DATA_MSK;
113
114 if (cobalt->have_hsma_rx)
115 irqs |= COBALT_SYSSTAT_VIHSMA_INT1_MSK |
116 COBALT_SYSSTAT_VIHSMA_INT2_MSK |
117 COBALT_SYSSTAT_VIHSMA_LOST_DATA_MSK;
118
119 if (cobalt->have_hsma_tx)
120 irqs |= COBALT_SYSSTAT_VOHSMA_INT1_MSK |
121 COBALT_SYSSTAT_VOHSMA_LOST_DATA_MSK |
122 COBALT_SYSSTAT_AUD_OUT_LOST_DATA_MSK;
123 /* Clear any existing interrupts */
124 cobalt_write_bar1(cobalt, COBALT_SYS_STAT_EDGE, 0xffffffff);
125 /* PIO Core interrupt mask register.
126 Enable ADV7604 INT1 interrupts */
127 cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK, irqs);
128 } else {
129 /* Disable all ADV7604 interrupts */
130 cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK, 0);
131 }
132}
133
134static unsigned cobalt_get_sd_nr(struct v4l2_subdev *sd)
135{
136 struct cobalt *cobalt = to_cobalt(sd->v4l2_dev);
137 unsigned i;
138
139 for (i = 0; i < COBALT_NUM_NODES; i++)
140 if (sd == cobalt->streams[i].sd)
141 return i;
142 cobalt_err("Invalid adv7604 subdev pointer!\n");
143 return 0;
144}
145
146static void cobalt_notify(struct v4l2_subdev *sd,
147 unsigned int notification, void *arg)
148{
149 struct cobalt *cobalt = to_cobalt(sd->v4l2_dev);
150 unsigned sd_nr = cobalt_get_sd_nr(sd);
151 struct cobalt_stream *s = &cobalt->streams[sd_nr];
152 bool hotplug = arg ? *((int *)arg) : false;
153
154 if (s->is_output)
155 return;
156
157 switch (notification) {
158 case ADV76XX_HOTPLUG:
159 cobalt_s_bit_sysctrl(cobalt,
160 COBALT_SYS_CTRL_HPD_TO_CONNECTOR_BIT(sd_nr), hotplug);
161 cobalt_dbg(1, "Set hotplug for adv %d to %d\n", sd_nr, hotplug);
162 break;
163 case V4L2_DEVICE_NOTIFY_EVENT:
164 cobalt_dbg(1, "Format changed for adv %d\n", sd_nr);
165 v4l2_event_queue(&s->vdev, arg);
166 break;
167 default:
168 break;
169 }
170}
171
172static int get_payload_size(u16 code)
173{
174 switch (code) {
175 case 0: return 128;
176 case 1: return 256;
177 case 2: return 512;
178 case 3: return 1024;
179 case 4: return 2048;
180 case 5: return 4096;
181 default: return 0;
182 }
183 return 0;
184}
185
186static const char *get_link_speed(u16 stat)
187{
188 switch (stat & PCI_EXP_LNKSTA_CLS) {
189 case 1: return "2.5 Gbit/s";
190 case 2: return "5 Gbit/s";
191 case 3: return "10 Gbit/s";
192 }
193 return "Unknown speed";
194}
195
196void cobalt_pcie_status_show(struct cobalt *cobalt)
197{
198 struct pci_dev *pci_dev = cobalt->pci_dev;
199 struct pci_dev *pci_bus_dev = cobalt->pci_dev->bus->self;
200 int offset;
201 int bus_offset;
202 u32 capa;
203 u16 stat, ctrl;
204
205 offset = pci_find_capability(pci_dev, PCI_CAP_ID_EXP);
206 bus_offset = pci_find_capability(pci_bus_dev, PCI_CAP_ID_EXP);
207
208 /* Device */
209 pci_read_config_dword(pci_dev, offset + PCI_EXP_DEVCAP, &capa);
210 pci_read_config_word(pci_dev, offset + PCI_EXP_DEVCTL, &ctrl);
211 pci_read_config_word(pci_dev, offset + PCI_EXP_DEVSTA, &stat);
212 cobalt_info("PCIe device capability 0x%08x: Max payload %d\n",
213 capa, get_payload_size(capa & PCI_EXP_DEVCAP_PAYLOAD));
214 cobalt_info("PCIe device control 0x%04x: Max payload %d. Max read request %d\n",
215 ctrl,
216 get_payload_size((ctrl & PCI_EXP_DEVCTL_PAYLOAD) >> 5),
217 get_payload_size((ctrl & PCI_EXP_DEVCTL_READRQ) >> 12));
218 cobalt_info("PCIe device status 0x%04x\n", stat);
219
220 /* Link */
221 pci_read_config_dword(pci_dev, offset + PCI_EXP_LNKCAP, &capa);
222 pci_read_config_word(pci_dev, offset + PCI_EXP_LNKCTL, &ctrl);
223 pci_read_config_word(pci_dev, offset + PCI_EXP_LNKSTA, &stat);
224 cobalt_info("PCIe link capability 0x%08x: %s per lane and %u lanes\n",
225 capa, get_link_speed(capa),
226 (capa & PCI_EXP_LNKCAP_MLW) >> 4);
227 cobalt_info("PCIe link control 0x%04x\n", ctrl);
228 cobalt_info("PCIe link status 0x%04x: %s per lane and %u lanes\n",
229 stat, get_link_speed(stat),
230 (stat & PCI_EXP_LNKSTA_NLW) >> 4);
231
232 /* Bus */
233 pci_read_config_dword(pci_bus_dev, bus_offset + PCI_EXP_LNKCAP, &capa);
234 cobalt_info("PCIe bus link capability 0x%08x: %s per lane and %u lanes\n",
235 capa, get_link_speed(capa),
236 (capa & PCI_EXP_LNKCAP_MLW) >> 4);
237
238 /* Slot */
239 pci_read_config_dword(pci_dev, offset + PCI_EXP_SLTCAP, &capa);
240 pci_read_config_word(pci_dev, offset + PCI_EXP_SLTCTL, &ctrl);
241 pci_read_config_word(pci_dev, offset + PCI_EXP_SLTSTA, &stat);
242 cobalt_info("PCIe slot capability 0x%08x\n", capa);
243 cobalt_info("PCIe slot control 0x%04x\n", ctrl);
244 cobalt_info("PCIe slot status 0x%04x\n", stat);
245}
246
247static unsigned pcie_link_get_lanes(struct cobalt *cobalt)
248{
249 struct pci_dev *pci_dev = cobalt->pci_dev;
250 unsigned offset;
251 u16 link;
252
253 offset = pci_find_capability(pci_dev, PCI_CAP_ID_EXP);
254 if (!offset)
255 return 0;
256 pci_read_config_word(pci_dev, offset + PCI_EXP_LNKSTA, &link);
257 return (link & PCI_EXP_LNKSTA_NLW) >> 4;
258}
259
260static unsigned pcie_bus_link_get_lanes(struct cobalt *cobalt)
261{
262 struct pci_dev *pci_dev = cobalt->pci_dev->bus->self;
263 unsigned offset;
264 u32 link;
265
266 offset = pci_find_capability(pci_dev, PCI_CAP_ID_EXP);
267 if (!offset)
268 return 0;
269 pci_read_config_dword(pci_dev, offset + PCI_EXP_LNKCAP, &link);
270 return (link & PCI_EXP_LNKCAP_MLW) >> 4;
271}
272
273static void msi_config_show(struct cobalt *cobalt, struct pci_dev *pci_dev)
274{
275 u16 ctrl, data;
276 u32 adrs_l, adrs_h;
277
278 pci_read_config_word(pci_dev, 0x52, &ctrl);
279 cobalt_info("MSI %s\n", ctrl & 1 ? "enable" : "disable");
280 cobalt_info("MSI multiple message: Capable %u. Enable %u\n",
281 (1 << ((ctrl >> 1) & 7)), (1 << ((ctrl >> 4) & 7)));
282 if (ctrl & 0x80)
283 cobalt_info("MSI: 64-bit address capable\n");
284 pci_read_config_dword(pci_dev, 0x54, &adrs_l);
285 pci_read_config_dword(pci_dev, 0x58, &adrs_h);
286 pci_read_config_word(pci_dev, 0x5c, &data);
287 if (ctrl & 0x80)
288 cobalt_info("MSI: Address 0x%08x%08x. Data 0x%04x\n",
289 adrs_h, adrs_l, data);
290 else
291 cobalt_info("MSI: Address 0x%08x. Data 0x%04x\n",
292 adrs_l, data);
293}
294
295static void cobalt_pci_iounmap(struct cobalt *cobalt, struct pci_dev *pci_dev)
296{
297 if (cobalt->bar0) {
298 pci_iounmap(pci_dev, cobalt->bar0);
299 cobalt->bar0 = 0;
300 }
301 if (cobalt->bar1) {
302 pci_iounmap(pci_dev, cobalt->bar1);
303 cobalt->bar1 = 0;
304 }
305}
306
307static void cobalt_free_msi(struct cobalt *cobalt, struct pci_dev *pci_dev)
308{
309 free_irq(pci_dev->irq, (void *)cobalt);
310
311 if (cobalt->msi_enabled)
312 pci_disable_msi(pci_dev);
313}
314
315static int cobalt_setup_pci(struct cobalt *cobalt, struct pci_dev *pci_dev,
316 const struct pci_device_id *pci_id)
317{
318 u32 ctrl;
319 int ret;
320
321 cobalt_dbg(1, "enabling pci device\n");
322
323 ret = pci_enable_device(pci_dev);
324 if (ret) {
325 cobalt_err("can't enable device\n");
326 return ret;
327 }
328 pci_set_master(pci_dev);
329 pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &cobalt->card_rev);
330 pci_read_config_word(pci_dev, PCI_DEVICE_ID, &cobalt->device_id);
331
332 switch (cobalt->device_id) {
333 case PCI_DEVICE_ID_COBALT:
334 cobalt_info("PCI Express interface from Omnitek\n");
335 break;
336 default:
337 cobalt_info("PCI Express interface provider is unknown!\n");
338 break;
339 }
340
341 if (pcie_link_get_lanes(cobalt) != 8) {
342 cobalt_err("PCI Express link width is not 8 lanes (%d)\n",
343 pcie_link_get_lanes(cobalt));
344 if (pcie_bus_link_get_lanes(cobalt) < 8)
345 cobalt_err("The current slot only supports %d lanes, at least 8 are needed\n",
346 pcie_bus_link_get_lanes(cobalt));
347 else
348 cobalt_err("The card is most likely not seated correctly in the PCIe slot\n");
349 ret = -EIO;
350 goto err_disable;
351 }
352
353 if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(64))) {
354 ret = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
355 if (ret) {
356 cobalt_err("no suitable DMA available\n");
357 goto err_disable;
358 }
359 }
360
361 ret = pci_request_regions(pci_dev, "cobalt");
362 if (ret) {
363 cobalt_err("error requesting regions\n");
364 goto err_disable;
365 }
366
367 cobalt_pcie_status_show(cobalt);
368
369 cobalt->bar0 = pci_iomap(pci_dev, 0, 0);
370 cobalt->bar1 = pci_iomap(pci_dev, 1, 0);
371 if (cobalt->bar1 == NULL) {
372 cobalt->bar1 = pci_iomap(pci_dev, 2, 0);
373 cobalt_info("64-bit BAR\n");
374 }
375 if (!cobalt->bar0 || !cobalt->bar1) {
376 ret = -EIO;
377 goto err_release;
378 }
379
380 /* Reset the video inputs before enabling any interrupts */
381 ctrl = cobalt_read_bar1(cobalt, COBALT_SYS_CTRL_BASE);
382 cobalt_write_bar1(cobalt, COBALT_SYS_CTRL_BASE, ctrl & ~0xf00);
383
384 /* Disable interrupts to prevent any spurious interrupts
385 from being generated. */
386 cobalt_set_interrupt(cobalt, false);
387
388 if (pci_enable_msi_range(pci_dev, 1, 1) < 1) {
389 cobalt_err("Could not enable MSI\n");
390 cobalt->msi_enabled = false;
391 ret = -EIO;
392 goto err_release;
393 }
394 msi_config_show(cobalt, pci_dev);
395 cobalt->msi_enabled = true;
396
397 /* Register IRQ */
398 if (request_irq(pci_dev->irq, cobalt_irq_handler, IRQF_SHARED,
399 cobalt->v4l2_dev.name, (void *)cobalt)) {
400 cobalt_err("Failed to register irq %d\n", pci_dev->irq);
401 ret = -EIO;
402 goto err_msi;
403 }
404
405 omni_sg_dma_init(cobalt);
406 return 0;
407
408err_msi:
409 pci_disable_msi(pci_dev);
410
411err_release:
412 cobalt_pci_iounmap(cobalt, pci_dev);
413 pci_release_regions(pci_dev);
414
415err_disable:
416 pci_disable_device(cobalt->pci_dev);
417 return ret;
418}
419
420static int cobalt_hdl_info_get(struct cobalt *cobalt)
421{
422 int i;
423
424 for (i = 0; i < COBALT_HDL_INFO_SIZE; i++)
425 cobalt->hdl_info[i] =
426 ioread8(cobalt->bar1 + COBALT_HDL_INFO_BASE + i);
427 cobalt->hdl_info[COBALT_HDL_INFO_SIZE - 1] = '\0';
428 if (strstr(cobalt->hdl_info, COBALT_HDL_SEARCH_STR))
429 return 0;
430
431 return 1;
432}
433
434static void cobalt_stream_struct_init(struct cobalt *cobalt)
435{
436 int i;
437
438 for (i = 0; i < COBALT_NUM_STREAMS; i++) {
439 struct cobalt_stream *s = &cobalt->streams[i];
440
441 s->cobalt = cobalt;
442 s->flags = 0;
443 s->is_audio = false;
444 s->is_output = false;
445 s->is_dummy = true;
446
447 /* The Memory DMA channels will always get a lower channel
448 * number than the FIFO DMA. Video input should map to the
449 * stream 0-3. The other can use stream struct from 4 and
450 * higher */
451 if (i <= COBALT_HSMA_IN_NODE) {
452 s->dma_channel = i + cobalt->first_fifo_channel;
453 s->video_channel = i;
454 } else if (i >= COBALT_AUDIO_IN_STREAM &&
455 i <= COBALT_AUDIO_IN_STREAM + 4) {
456 s->dma_channel = 6 + i - COBALT_AUDIO_IN_STREAM;
457 s->is_audio = true;
458 s->video_channel = i - COBALT_AUDIO_IN_STREAM;
459 } else if (i == COBALT_HSMA_OUT_NODE) {
460 s->dma_channel = 11;
461 s->is_output = true;
462 s->video_channel = 5;
463 } else if (i == COBALT_AUDIO_OUT_STREAM) {
464 s->dma_channel = 12;
465 s->is_audio = true;
466 s->is_output = true;
467 s->video_channel = 5;
468 } else {
469 /* FIXME: Memory DMA for debug purpose */
470 s->dma_channel = i - COBALT_NUM_NODES;
471 }
472 cobalt_info("stream #%d -> dma channel #%d <- video channel %d\n",
473 i, s->dma_channel, s->video_channel);
474 }
475}
476
477static int cobalt_subdevs_init(struct cobalt *cobalt)
478{
479 static struct adv76xx_platform_data adv7604_pdata = {
480 .disable_pwrdnb = 1,
481 .ain_sel = ADV7604_AIN7_8_9_NC_SYNC_3_1,
482 .bus_order = ADV7604_BUS_ORDER_BRG,
483 .blank_data = 1,
484 .op_656_range = 1,
485 .op_format_mode_sel = ADV7604_OP_FORMAT_MODE0,
486 .int1_config = ADV76XX_INT1_CONFIG_ACTIVE_HIGH,
487 .dr_str_data = ADV76XX_DR_STR_HIGH,
488 .dr_str_clk = ADV76XX_DR_STR_HIGH,
489 .dr_str_sync = ADV76XX_DR_STR_HIGH,
490 .hdmi_free_run_mode = 1,
491 .inv_vs_pol = 1,
492 .inv_hs_pol = 1,
493 };
494 static struct i2c_board_info adv7604_info = {
495 .type = "adv7604",
496 .addr = 0x20,
497 .platform_data = &adv7604_pdata,
498 };
499
500 struct cobalt_stream *s = cobalt->streams;
501 int i;
502
503 for (i = 0; i < COBALT_NUM_INPUTS; i++) {
504 struct v4l2_subdev_format sd_fmt = {
505 .pad = ADV7604_PAD_SOURCE,
506 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
507 .format.code = MEDIA_BUS_FMT_YUYV8_1X16,
508 };
509 struct v4l2_subdev_edid cobalt_edid = {
510 .pad = ADV76XX_PAD_HDMI_PORT_A,
511 .start_block = 0,
512 .blocks = 2,
513 .edid = edid,
514 };
515 int err;
516
517 s[i].pad_source = ADV7604_PAD_SOURCE;
518 s[i].i2c_adap = &cobalt->i2c_adap[i];
519 if (s[i].i2c_adap->dev.parent == NULL)
520 continue;
521 cobalt_s_bit_sysctrl(cobalt,
522 COBALT_SYS_CTRL_NRESET_TO_HDMI_BIT(i), 1);
523 s[i].sd = v4l2_i2c_new_subdev_board(&cobalt->v4l2_dev,
524 s[i].i2c_adap, &adv7604_info, NULL);
525 if (!s[i].sd) {
526 if (cobalt_ignore_err)
527 continue;
528 return -ENODEV;
529 }
530 err = v4l2_subdev_call(s[i].sd, video, s_routing,
531 ADV76XX_PAD_HDMI_PORT_A, 0, 0);
532 if (err)
533 return err;
534 err = v4l2_subdev_call(s[i].sd, pad, set_edid,
535 &cobalt_edid);
536 if (err)
537 return err;
538 err = v4l2_subdev_call(s[i].sd, pad, set_fmt, NULL,
539 &sd_fmt);
540 if (err)
541 return err;
542 /* Reset channel video module */
543 cobalt_s_bit_sysctrl(cobalt,
544 COBALT_SYS_CTRL_VIDEO_RX_RESETN_BIT(i), 0);
545 mdelay(2);
546 cobalt_s_bit_sysctrl(cobalt,
547 COBALT_SYS_CTRL_VIDEO_RX_RESETN_BIT(i), 1);
548 mdelay(1);
549 s[i].is_dummy = false;
550 cobalt->streams[i + COBALT_AUDIO_IN_STREAM].is_dummy = false;
551 }
552 return 0;
553}
554
555static int cobalt_subdevs_hsma_init(struct cobalt *cobalt)
556{
557 static struct adv7842_platform_data adv7842_pdata = {
558 .disable_pwrdnb = 1,
559 .ain_sel = ADV7842_AIN1_2_3_NC_SYNC_1_2,
560 .bus_order = ADV7842_BUS_ORDER_RBG,
561 .op_format_mode_sel = ADV7842_OP_FORMAT_MODE0,
562 .blank_data = 1,
563 .op_656_range = 1,
564 .dr_str_data = 3,
565 .dr_str_clk = 3,
566 .dr_str_sync = 3,
567 .mode = ADV7842_MODE_HDMI,
568 .hdmi_free_run_enable = 1,
569 .vid_std_select = ADV7842_HDMI_COMP_VID_STD_HD_1250P,
570 .i2c_sdp_io = 0x4a,
571 .i2c_sdp = 0x48,
572 .i2c_cp = 0x22,
573 .i2c_vdp = 0x24,
574 .i2c_afe = 0x26,
575 .i2c_hdmi = 0x34,
576 .i2c_repeater = 0x32,
577 .i2c_edid = 0x36,
578 .i2c_infoframe = 0x3e,
579 .i2c_cec = 0x40,
580 .i2c_avlink = 0x42,
581 };
582 static struct i2c_board_info adv7842_info = {
583 .type = "adv7842",
584 .addr = 0x20,
585 .platform_data = &adv7842_pdata,
586 };
587 static struct v4l2_subdev_format sd_fmt = {
588 .pad = ADV7842_PAD_SOURCE,
589 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
590 .format.code = MEDIA_BUS_FMT_YUYV8_1X16,
591 };
592 static struct adv7511_platform_data adv7511_pdata = {
593 .i2c_edid = 0x7e >> 1,
594 .i2c_cec = 0x7c >> 1,
595 .cec_clk = 12000000,
596 };
597 static struct i2c_board_info adv7511_info = {
598 .type = "adv7511",
599 .addr = 0x39, /* 0x39 or 0x3d */
600 .platform_data = &adv7511_pdata,
601 };
602 struct v4l2_subdev_edid cobalt_edid = {
603 .pad = ADV7842_EDID_PORT_A,
604 .start_block = 0,
605 .blocks = 2,
606 .edid = edid,
607 };
608 struct cobalt_stream *s = &cobalt->streams[COBALT_HSMA_IN_NODE];
609
610 s->i2c_adap = &cobalt->i2c_adap[COBALT_NUM_ADAPTERS - 1];
611 if (s->i2c_adap->dev.parent == NULL)
612 return 0;
613 cobalt_s_bit_sysctrl(cobalt, COBALT_SYS_CTRL_NRESET_TO_HDMI_BIT(4), 1);
614
615 s->sd = v4l2_i2c_new_subdev_board(&cobalt->v4l2_dev,
616 s->i2c_adap, &adv7842_info, NULL);
617 if (s->sd) {
618 int err = v4l2_subdev_call(s->sd, pad, set_edid, &cobalt_edid);
619
620 if (err)
621 return err;
622 err = v4l2_subdev_call(s->sd, pad, set_fmt, NULL,
623 &sd_fmt);
624 if (err)
625 return err;
626 cobalt->have_hsma_rx = true;
627 s->pad_source = ADV7842_PAD_SOURCE;
628 s->is_dummy = false;
629 cobalt->streams[4 + COBALT_AUDIO_IN_STREAM].is_dummy = false;
630 /* Reset channel video module */
631 cobalt_s_bit_sysctrl(cobalt,
632 COBALT_SYS_CTRL_VIDEO_RX_RESETN_BIT(4), 0);
633 mdelay(2);
634 cobalt_s_bit_sysctrl(cobalt,
635 COBALT_SYS_CTRL_VIDEO_RX_RESETN_BIT(4), 1);
636 mdelay(1);
637 return err;
638 }
639 cobalt_s_bit_sysctrl(cobalt, COBALT_SYS_CTRL_NRESET_TO_HDMI_BIT(4), 0);
640 cobalt_s_bit_sysctrl(cobalt, COBALT_SYS_CTRL_PWRDN0_TO_HSMA_TX_BIT, 0);
641 s++;
642 s->i2c_adap = &cobalt->i2c_adap[COBALT_NUM_ADAPTERS - 1];
643 s->sd = v4l2_i2c_new_subdev_board(&cobalt->v4l2_dev,
644 s->i2c_adap, &adv7511_info, NULL);
645 if (s->sd) {
646 /* A transmitter is hooked up, so we can set this bit */
647 cobalt_s_bit_sysctrl(cobalt,
648 COBALT_SYS_CTRL_HSMA_TX_ENABLE_BIT, 1);
649 cobalt_s_bit_sysctrl(cobalt,
650 COBALT_SYS_CTRL_VIDEO_RX_RESETN_BIT(4), 0);
651 cobalt_s_bit_sysctrl(cobalt,
652 COBALT_SYS_CTRL_VIDEO_TX_RESETN_BIT, 1);
653 cobalt->have_hsma_tx = true;
654 v4l2_subdev_call(s->sd, core, s_power, 1);
655 v4l2_subdev_call(s->sd, video, s_stream, 1);
656 v4l2_subdev_call(s->sd, audio, s_stream, 1);
657 v4l2_ctrl_s_ctrl(v4l2_ctrl_find(s->sd->ctrl_handler,
658 V4L2_CID_DV_TX_MODE), V4L2_DV_TX_MODE_HDMI);
659 s->is_dummy = false;
660 cobalt->streams[COBALT_AUDIO_OUT_STREAM].is_dummy = false;
661 return 0;
662 }
663 return -ENODEV;
664}
665
666static int cobalt_probe(struct pci_dev *pci_dev,
667 const struct pci_device_id *pci_id)
668{
669 struct cobalt *cobalt;
670 int retval = 0;
671 int i;
672
673 /* FIXME - module parameter arrays constrain max instances */
674 i = atomic_inc_return(&cobalt_instance) - 1;
675
676 cobalt = kzalloc(sizeof(struct cobalt), GFP_ATOMIC);
677 if (cobalt == NULL)
678 return -ENOMEM;
679 cobalt->pci_dev = pci_dev;
680 cobalt->instance = i;
681
682 cobalt->alloc_ctx = vb2_dma_sg_init_ctx(&pci_dev->dev);
683 if (IS_ERR(cobalt->alloc_ctx)) {
684 kfree(cobalt);
685 return -ENOMEM;
686 }
687
688 retval = v4l2_device_register(&pci_dev->dev, &cobalt->v4l2_dev);
689 if (retval) {
690 pr_err("cobalt: v4l2_device_register of card %d failed\n",
691 cobalt->instance);
692 vb2_dma_sg_cleanup_ctx(cobalt->alloc_ctx);
693 kfree(cobalt);
694 return retval;
695 }
696 snprintf(cobalt->v4l2_dev.name, sizeof(cobalt->v4l2_dev.name),
697 "cobalt-%d", cobalt->instance);
698 cobalt->v4l2_dev.notify = cobalt_notify;
699 cobalt_info("Initializing card %d\n", cobalt->instance);
700
701 cobalt->irq_work_queues =
702 create_singlethread_workqueue(cobalt->v4l2_dev.name);
703 if (cobalt->irq_work_queues == NULL) {
704 cobalt_err("Could not create workqueue\n");
705 retval = -ENOMEM;
706 goto err;
707 }
708
709 INIT_WORK(&cobalt->irq_work_queue, cobalt_irq_work_handler);
710
711 /* PCI Device Setup */
712 retval = cobalt_setup_pci(cobalt, pci_dev, pci_id);
713 if (retval != 0)
714 goto err_wq;
715
716 /* Show HDL version info */
717 if (cobalt_hdl_info_get(cobalt))
718 cobalt_info("Not able to read the HDL info\n");
719 else
720 cobalt_info("%s", cobalt->hdl_info);
721
722 retval = cobalt_i2c_init(cobalt);
723 if (retval)
724 goto err_pci;
725
726 cobalt_stream_struct_init(cobalt);
727
728 retval = cobalt_subdevs_init(cobalt);
729 if (retval)
730 goto err_i2c;
731
732 if (!(cobalt_read_bar1(cobalt, COBALT_SYS_STAT_BASE) &
733 COBALT_SYSSTAT_HSMA_PRSNTN_MSK)) {
734 retval = cobalt_subdevs_hsma_init(cobalt);
735 if (retval)
736 goto err_i2c;
737 }
738
739 retval = v4l2_device_register_subdev_nodes(&cobalt->v4l2_dev);
740 if (retval)
741 goto err_i2c;
742 retval = cobalt_nodes_register(cobalt);
743 if (retval) {
744 cobalt_err("Error %d registering device nodes\n", retval);
745 goto err_i2c;
746 }
747 cobalt_set_interrupt(cobalt, true);
748 v4l2_device_call_all(&cobalt->v4l2_dev, 0, core,
749 interrupt_service_routine, 0, NULL);
750
751 cobalt_info("Initialized cobalt card\n");
752
753 cobalt_flash_probe(cobalt);
754
755 return 0;
756
757err_i2c:
758 cobalt_i2c_exit(cobalt);
759 cobalt_s_bit_sysctrl(cobalt, COBALT_SYS_CTRL_HSMA_TX_ENABLE_BIT, 0);
760err_pci:
761 cobalt_free_msi(cobalt, pci_dev);
762 cobalt_pci_iounmap(cobalt, pci_dev);
763 pci_release_regions(cobalt->pci_dev);
764 pci_disable_device(cobalt->pci_dev);
765err_wq:
766 destroy_workqueue(cobalt->irq_work_queues);
767err:
768 if (retval == 0)
769 retval = -ENODEV;
770 cobalt_err("error %d on initialization\n", retval);
771
772 v4l2_device_unregister(&cobalt->v4l2_dev);
773 vb2_dma_sg_cleanup_ctx(cobalt->alloc_ctx);
774 kfree(cobalt);
775 return retval;
776}
777
778static void cobalt_remove(struct pci_dev *pci_dev)
779{
780 struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
781 struct cobalt *cobalt = to_cobalt(v4l2_dev);
782 int i;
783
784 cobalt_flash_remove(cobalt);
785 cobalt_set_interrupt(cobalt, false);
786 flush_workqueue(cobalt->irq_work_queues);
787 cobalt_nodes_unregister(cobalt);
788 for (i = 0; i < COBALT_NUM_ADAPTERS; i++) {
789 struct v4l2_subdev *sd = cobalt->streams[i].sd;
790 struct i2c_client *client;
791
792 if (sd == NULL)
793 continue;
794 client = v4l2_get_subdevdata(sd);
795 v4l2_device_unregister_subdev(sd);
796 i2c_unregister_device(client);
797 }
798 cobalt_i2c_exit(cobalt);
799 cobalt_free_msi(cobalt, pci_dev);
800 cobalt_s_bit_sysctrl(cobalt, COBALT_SYS_CTRL_HSMA_TX_ENABLE_BIT, 0);
801 cobalt_pci_iounmap(cobalt, pci_dev);
802 pci_release_regions(cobalt->pci_dev);
803 pci_disable_device(cobalt->pci_dev);
804 destroy_workqueue(cobalt->irq_work_queues);
805
806 cobalt_info("removed cobalt card\n");
807
808 v4l2_device_unregister(v4l2_dev);
809 vb2_dma_sg_cleanup_ctx(cobalt->alloc_ctx);
810 kfree(cobalt);
811}
812
813/* define a pci_driver for card detection */
814static struct pci_driver cobalt_pci_driver = {
815 .name = "cobalt",
816 .id_table = cobalt_pci_tbl,
817 .probe = cobalt_probe,
818 .remove = cobalt_remove,
819};
820
821module_pci_driver(cobalt_pci_driver);