aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/video/cx18/cx18-driver.c18
-rw-r--r--drivers/media/video/cx18/cx18-driver.h4
-rw-r--r--drivers/media/video/cx18/cx18-io.c115
-rw-r--r--drivers/media/video/cx18/cx18-io.h115
-rw-r--r--drivers/media/video/cx18/cx18-queue.c2
-rw-r--r--drivers/media/video/cx18/cx18-queue.h2
6 files changed, 168 insertions, 88 deletions
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index d31e1ec8d14c..202b28190148 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -4,6 +4,7 @@
4 * Derived from ivtv-driver.c 4 * Derived from ivtv-driver.c
5 * 5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> 6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 * Copyright (C) 2008 Andy Walls <awalls@radix.net>
7 * 8 *
8 * This program is free software; you can redistribute it and/or modify 9 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 10 * it under the terms of the GNU General Public License as published by
@@ -74,10 +75,14 @@ static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
74 -1, -1, -1, -1, -1, -1, -1, -1, 75 -1, -1, -1, -1, -1, -1, -1, -1,
75 -1, -1, -1, -1, -1, -1, -1, -1, 76 -1, -1, -1, -1, -1, -1, -1, -1,
76 -1, -1, -1, -1, -1, -1, -1, -1 }; 77 -1, -1, -1, -1, -1, -1, -1, -1 };
77 78static int mmio_ndelay[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
79 -1, -1, -1, -1, -1, -1, -1, -1,
80 -1, -1, -1, -1, -1, -1, -1, -1,
81 -1, -1, -1, -1, -1, -1, -1, -1 };
78static unsigned cardtype_c = 1; 82static unsigned cardtype_c = 1;
79static unsigned tuner_c = 1; 83static unsigned tuner_c = 1;
80static unsigned radio_c = 1; 84static unsigned radio_c = 1;
85static int mmio_ndelay_c = 1;
81static char pal[] = "--"; 86static char pal[] = "--";
82static char secam[] = "--"; 87static char secam[] = "--";
83static char ntsc[] = "-"; 88static char ntsc[] = "-";
@@ -96,6 +101,7 @@ int cx18_debug;
96module_param_array(tuner, int, &tuner_c, 0644); 101module_param_array(tuner, int, &tuner_c, 0644);
97module_param_array(radio, bool, &radio_c, 0644); 102module_param_array(radio, bool, &radio_c, 0644);
98module_param_array(cardtype, int, &cardtype_c, 0644); 103module_param_array(cardtype, int, &cardtype_c, 0644);
104module_param_array(mmio_ndelay, int, &mmio_ndelay_c, 0644);
99module_param_string(pal, pal, sizeof(pal), 0644); 105module_param_string(pal, pal, sizeof(pal), 0644);
100module_param_string(secam, secam, sizeof(secam), 0644); 106module_param_string(secam, secam, sizeof(secam), 0644);
101module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); 107module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
@@ -141,6 +147,11 @@ MODULE_PARM_DESC(debug,
141MODULE_PARM_DESC(cx18_pci_latency, 147MODULE_PARM_DESC(cx18_pci_latency,
142 "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n" 148 "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
143 "\t\t\tDefault: Yes"); 149 "\t\t\tDefault: Yes");
150MODULE_PARM_DESC(mmio_ndelay,
151 "Delay (ns) for each CX23418 memory mapped IO access.\n"
152 "\t\t\tTry larger values that are close to a multiple of the\n"
153 "\t\t\tPCI clock period, 30.3 ns, if your card doesn't work.\n"
154 "\t\t\tDefault: " __stringify(CX18_DEFAULT_MMIO_NDELAY));
144MODULE_PARM_DESC(enc_mpg_buffers, 155MODULE_PARM_DESC(enc_mpg_buffers,
145 "Encoder MPG Buffers (in MB)\n" 156 "Encoder MPG Buffers (in MB)\n"
146 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS)); 157 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS));
@@ -357,6 +368,11 @@ static void cx18_process_options(struct cx18 *cx)
357 cx->options.tuner = tuner[cx->num]; 368 cx->options.tuner = tuner[cx->num];
358 cx->options.radio = radio[cx->num]; 369 cx->options.radio = radio[cx->num];
359 370
371 if (mmio_ndelay[cx->num] < 0)
372 cx->options.mmio_ndelay = CX18_DEFAULT_MMIO_NDELAY;
373 else
374 cx->options.mmio_ndelay = mmio_ndelay[cx->num];
375
360 cx->std = cx18_parse_std(cx); 376 cx->std = cx18_parse_std(cx);
361 if (cx->options.cardtype == -1) { 377 if (cx->options.cardtype == -1) {
362 CX18_INFO("Ignore card\n"); 378 CX18_INFO("Ignore card\n");
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index 2cfdbe445820..cc6f288a6da8 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -63,6 +63,9 @@
63# error "This driver requires kernel PCI support." 63# error "This driver requires kernel PCI support."
64#endif 64#endif
65 65
66/* Default delay to throttle mmio access to the CX23418 so it doesn't choke */
67#define CX18_DEFAULT_MMIO_NDELAY 31 /* 30.3 ns = 1 PCI clock(s) / 33 MHz */
68
66#define CX18_MEM_OFFSET 0x00000000 69#define CX18_MEM_OFFSET 0x00000000
67#define CX18_MEM_SIZE 0x04000000 70#define CX18_MEM_SIZE 0x04000000
68#define CX18_REG_OFFSET 0x02000000 71#define CX18_REG_OFFSET 0x02000000
@@ -176,6 +179,7 @@ struct cx18_options {
176 int cardtype; /* force card type on load */ 179 int cardtype; /* force card type on load */
177 int tuner; /* set tuner on load */ 180 int tuner; /* set tuner on load */
178 int radio; /* enable/disable radio */ 181 int radio; /* enable/disable radio */
182 unsigned long mmio_ndelay; /* delay in ns after every PCI mmio access */
179}; 183};
180 184
181/* per-buffer bit flags */ 185/* per-buffer bit flags */
diff --git a/drivers/media/video/cx18/cx18-io.c b/drivers/media/video/cx18/cx18-io.c
index c53d9b6e5e46..d92f627d35e4 100644
--- a/drivers/media/video/cx18/cx18-io.c
+++ b/drivers/media/video/cx18/cx18-io.c
@@ -21,76 +21,69 @@
21 */ 21 */
22 22
23#include "cx18-driver.h" 23#include "cx18-driver.h"
24#include "cx18-io.h"
24#include "cx18-irq.h" 25#include "cx18-irq.h"
25 26
26void cx18_raw_writel(struct cx18 *cx, u32 val, void __iomem *addr)
27{
28 __raw_writel(val, addr);
29}
30
31u32 cx18_raw_readl(struct cx18 *cx, const void __iomem *addr)
32{
33 return __raw_readl(addr);
34}
35
36u32 cx18_write_sync(struct cx18 *cx, u32 val, void __iomem *addr)
37{
38 writel(val, addr);
39 return readl(addr);
40}
41
42void cx18_writel(struct cx18 *cx, u32 val, void __iomem *addr)
43{
44 writel(val, addr);
45}
46
47u32 cx18_readl(struct cx18 *cx, const void __iomem *addr)
48{
49 return readl(addr);
50}
51
52
53/* Access "register" region of CX23418 memory mapped I/O */
54u32 cx18_read_reg(struct cx18 *cx, u32 reg)
55{
56 return readl(cx->reg_mem + reg);
57}
58
59void cx18_write_reg(struct cx18 *cx, u32 val, u32 reg)
60{
61 writel(val, cx->reg_mem + reg);
62}
63
64u32 cx18_write_reg_sync(struct cx18 *cx, u32 val, u32 reg)
65{
66 return cx18_write_sync(cx, val, cx->reg_mem + reg);
67}
68
69/* Access "encoder memory" region of CX23418 memory mapped I/O */
70u32 cx18_read_enc(struct cx18 *cx, u32 addr)
71{
72 return readl(cx->enc_mem + addr);
73}
74
75void cx18_write_enc(struct cx18 *cx, u32 val, u32 addr)
76{
77 writel(val, cx->enc_mem + addr);
78}
79
80u32 cx18_write_enc_sync(struct cx18 *cx, u32 val, u32 addr)
81{
82 return cx18_write_sync(cx, val, cx->enc_mem + addr);
83}
84
85void cx18_memcpy_fromio(struct cx18 *cx, void *to, 27void cx18_memcpy_fromio(struct cx18 *cx, void *to,
86 const void __iomem *from, unsigned int len) 28 const void __iomem *from, unsigned int len)
87{ 29{
88 memcpy_fromio(to, from, len); 30 /* Align reads on the CX23418's addresses */
31 if ((len > 0) && ((unsigned)from & 1)) {
32 *((u8 *)to) = cx18_readb(cx, from);
33 len--;
34 to++;
35 from++;
36 }
37 if ((len > 1) && ((unsigned)from & 2)) {
38 *((u16 *)to) = cx18_raw_readw(cx, from);
39 len -= 2;
40 to += 2;
41 from += 2;
42 }
43 while (len > 3) {
44 *((u32 *)to) = cx18_raw_readl(cx, from);
45 len -= 4;
46 to += 4;
47 from += 4;
48 }
49 if (len > 1) {
50 *((u16 *)to) = cx18_raw_readw(cx, from);
51 len -= 2;
52 to += 2;
53 from += 2;
54 }
55 if (len > 0)
56 *((u8 *)to) = cx18_readb(cx, from);
89} 57}
90 58
91void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count) 59void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count)
92{ 60{
93 memset_io(addr, val, count); 61 u16 val2 = val | (val << 8);
62 u32 val4 = val2 | (val2 << 16);
63
64 /* Align writes on the CX23418's addresses */
65 if ((count > 0) && ((unsigned)addr & 1)) {
66 cx18_writeb(cx, (u8) val, addr);
67 count--;
68 addr++;
69 }
70 if ((count > 1) && ((unsigned)addr & 2)) {
71 cx18_writew(cx, val2, addr);
72 count -= 2;
73 addr += 2;
74 }
75 while (count > 3) {
76 cx18_writel(cx, val4, addr);
77 count -= 4;
78 addr += 4;
79 }
80 if (count > 1) {
81 cx18_writew(cx, val2, addr);
82 count -= 2;
83 addr += 2;
84 }
85 if (count > 0)
86 cx18_writeb(cx, (u8) val, addr);
94} 87}
95 88
96void cx18_sw1_irq_enable(struct cx18 *cx, u32 val) 89void cx18_sw1_irq_enable(struct cx18 *cx, u32 val)
diff --git a/drivers/media/video/cx18/cx18-io.h b/drivers/media/video/cx18/cx18-io.h
index 7c08c0add490..7ab7be2531ca 100644
--- a/drivers/media/video/cx18/cx18-io.h
+++ b/drivers/media/video/cx18/cx18-io.h
@@ -25,38 +25,109 @@
25 25
26#include "cx18-driver.h" 26#include "cx18-driver.h"
27 27
28/* This is a PCI post thing, where if the pci register is not read, then 28static inline void cx18_io_delay(struct cx18 *cx)
29 the write doesn't always take effect right away. By reading back the 29{
30 register any pending PCI writes will be performed (in order), and so 30 if (cx->options.mmio_ndelay)
31 you can be sure that the writes are guaranteed to be done. 31 ndelay(cx->options.mmio_ndelay);
32}
32 33
33 Rarely needed, only in some timing sensitive cases. 34/* Non byteswapping memory mapped IO */
34 Apparently if this is not done some motherboards seem 35static inline void cx18_raw_writel(struct cx18 *cx, u32 val, void __iomem *addr)
35 to kill the firmware and get into the broken state until computer is 36{
36 rebooted. */ 37 __raw_writel(val, addr);
37u32 cx18_write_sync(struct cx18 *cx, u32 val, void __iomem *addr); 38 cx18_io_delay(cx);
39}
38 40
39void cx18_writel(struct cx18 *cx, u32 val, void __iomem *addr); 41static inline u32 cx18_raw_readl(struct cx18 *cx, const void __iomem *addr)
40u32 cx18_readl(struct cx18 *cx, const void __iomem *addr); 42{
43 u32 ret = __raw_readl(addr);
44 cx18_io_delay(cx);
45 return ret;
46}
41 47
42/* No endiannes conversion calls */ 48static inline u16 cx18_raw_readw(struct cx18 *cx, const void __iomem *addr)
43void cx18_raw_writel(struct cx18 *cx, u32 val, void __iomem *addr); 49{
44u32 cx18_raw_readl(struct cx18 *cx, const void __iomem *addr); 50 u16 ret = __raw_readw(addr);
51 cx18_io_delay(cx);
52 return ret;
53}
45 54
46/* Access "register" region of CX23418 memory mapped I/O */ 55/* Normal memory mapped IO */
47u32 cx18_read_reg(struct cx18 *cx, u32 reg); 56static inline void cx18_writel(struct cx18 *cx, u32 val, void __iomem *addr)
48void cx18_write_reg(struct cx18 *cx, u32 val, u32 reg); 57{
49u32 cx18_write_reg_sync(struct cx18 *cx, u32 val, u32 reg); 58 writel(val, addr);
59 cx18_io_delay(cx);
60}
50 61
51/* Access "encoder memory" region of CX23418 memory mapped I/O */ 62static inline void cx18_writew(struct cx18 *cx, u16 val, void __iomem *addr)
52u32 cx18_read_enc(struct cx18 *cx, u32 addr); 63{
53void cx18_write_enc(struct cx18 *cx, u32 val, u32 addr); 64 writew(val, addr);
54u32 cx18_write_enc_sync(struct cx18 *cx, u32 val, u32 addr); 65 cx18_io_delay(cx);
66}
67
68static inline void cx18_writeb(struct cx18 *cx, u8 val, void __iomem *addr)
69{
70 writeb(val, addr);
71 cx18_io_delay(cx);
72}
73
74static inline u32 cx18_readl(struct cx18 *cx, const void __iomem *addr)
75{
76 u32 ret = readl(addr);
77 cx18_io_delay(cx);
78 return ret;
79}
80
81static inline u8 cx18_readb(struct cx18 *cx, const void __iomem *addr)
82{
83 u8 ret = readb(addr);
84 cx18_io_delay(cx);
85 return ret;
86}
87
88static inline u32 cx18_write_sync(struct cx18 *cx, u32 val, void __iomem *addr)
89{
90 cx18_writel(cx, val, addr);
91 return cx18_readl(cx, addr);
92}
55 93
56void cx18_memcpy_fromio(struct cx18 *cx, void *to, 94void cx18_memcpy_fromio(struct cx18 *cx, void *to,
57 const void __iomem *from, unsigned int len); 95 const void __iomem *from, unsigned int len);
58void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count); 96void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count);
59 97
98/* Access "register" region of CX23418 memory mapped I/O */
99static inline void cx18_write_reg(struct cx18 *cx, u32 val, u32 reg)
100{
101 cx18_writel(cx, val, cx->reg_mem + reg);
102}
103
104static inline u32 cx18_read_reg(struct cx18 *cx, u32 reg)
105{
106 return cx18_readl(cx, cx->reg_mem + reg);
107}
108
109static inline u32 cx18_write_reg_sync(struct cx18 *cx, u32 val, u32 reg)
110{
111 return cx18_write_sync(cx, val, cx->reg_mem + reg);
112}
113
114/* Access "encoder memory" region of CX23418 memory mapped I/O */
115static inline void cx18_write_enc(struct cx18 *cx, u32 val, u32 addr)
116{
117 cx18_writel(cx, val, cx->enc_mem + addr);
118}
119
120static inline u32 cx18_read_enc(struct cx18 *cx, u32 addr)
121{
122 return cx18_readl(cx, cx->enc_mem + addr);
123}
124
125static inline u32 cx18_write_enc_sync(struct cx18 *cx, u32 val, u32 addr)
126{
127 return cx18_write_sync(cx, val, cx->enc_mem + addr);
128}
129
130
60void cx18_sw1_irq_enable(struct cx18 *cx, u32 val); 131void cx18_sw1_irq_enable(struct cx18 *cx, u32 val);
61void cx18_sw1_irq_disable(struct cx18 *cx, u32 val); 132void cx18_sw1_irq_disable(struct cx18 *cx, u32 val);
62void cx18_sw2_irq_enable(struct cx18 *cx, u32 val); 133void cx18_sw2_irq_enable(struct cx18 *cx, u32 val);
diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c
index 48976833e238..a33ba04a2686 100644
--- a/drivers/media/video/cx18/cx18-queue.c
+++ b/drivers/media/video/cx18/cx18-queue.c
@@ -170,7 +170,6 @@ int cx18_stream_alloc(struct cx18_stream *s)
170 } 170 }
171 buf->id = cx->buffer_id++; 171 buf->id = cx->buffer_id++;
172 INIT_LIST_HEAD(&buf->list); 172 INIT_LIST_HEAD(&buf->list);
173 /* FIXME - check for mmio */
174 buf->dma_handle = pci_map_single(s->cx->dev, 173 buf->dma_handle = pci_map_single(s->cx->dev,
175 buf->buf, s->buf_size, s->dma); 174 buf->buf, s->buf_size, s->dma);
176 cx18_buf_sync_for_cpu(s, buf); 175 cx18_buf_sync_for_cpu(s, buf);
@@ -194,7 +193,6 @@ void cx18_stream_free(struct cx18_stream *s)
194 193
195 /* empty q_free */ 194 /* empty q_free */
196 while ((buf = cx18_dequeue(s, &s->q_free))) { 195 while ((buf = cx18_dequeue(s, &s->q_free))) {
197 /* FIXME - check for mmio */
198 pci_unmap_single(s->cx->dev, buf->dma_handle, 196 pci_unmap_single(s->cx->dev, buf->dma_handle,
199 s->buf_size, s->dma); 197 s->buf_size, s->dma);
200 kfree(buf->buf); 198 kfree(buf->buf);
diff --git a/drivers/media/video/cx18/cx18-queue.h b/drivers/media/video/cx18/cx18-queue.h
index 0c7df932d176..7f93bb13c09f 100644
--- a/drivers/media/video/cx18/cx18-queue.h
+++ b/drivers/media/video/cx18/cx18-queue.h
@@ -28,7 +28,6 @@
28static inline void cx18_buf_sync_for_cpu(struct cx18_stream *s, 28static inline void cx18_buf_sync_for_cpu(struct cx18_stream *s,
29 struct cx18_buffer *buf) 29 struct cx18_buffer *buf)
30{ 30{
31 /* FIXME check IO transfers */
32 pci_dma_sync_single_for_cpu(s->cx->dev, buf->dma_handle, 31 pci_dma_sync_single_for_cpu(s->cx->dev, buf->dma_handle,
33 s->buf_size, s->dma); 32 s->buf_size, s->dma);
34} 33}
@@ -36,7 +35,6 @@ static inline void cx18_buf_sync_for_cpu(struct cx18_stream *s,
36static inline void cx18_buf_sync_for_device(struct cx18_stream *s, 35static inline void cx18_buf_sync_for_device(struct cx18_stream *s,
37 struct cx18_buffer *buf) 36 struct cx18_buffer *buf)
38{ 37{
39 /* FIXME check IO transfers */
40 pci_dma_sync_single_for_device(s->cx->dev, buf->dma_handle, 38 pci_dma_sync_single_for_device(s->cx->dev, buf->dma_handle,
41 s->buf_size, s->dma); 39 s->buf_size, s->dma);
42} 40}