diff options
author | Patrick Boettcher <pb@linuxtv.org> | 2005-07-07 20:57:49 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-07-07 21:23:56 -0400 |
commit | 64221be7b9006338e4a45228f013e467ee4bf045 (patch) | |
tree | acf137799c31c966f6d8083aee39c27f331905ab /drivers/media/dvb/b2c2/flexcop-dma.c | |
parent | 2819639b5630cd26d399ee0481be9a752280cf4d (diff) |
[PATCH] dvb: flexcop: woraround irq stop problem
The flexcop chip often stops generating interrupts after some hours of
operation. Apparently this can be fixed by resetting register block 0x300 at
each channel change (this is not detailed in the flexcop data books).
This patch also restructures DMA handling and adds a bit of debug code for the
irq problem in case it still happens for someone.
Signed-off-by: Patrick Boettcher <pb@linuxtv.org>
Signed-off-by: Johannes Stezenbach <js@linuxtv.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/media/dvb/b2c2/flexcop-dma.c')
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-dma.c | 165 |
1 files changed, 111 insertions, 54 deletions
diff --git a/drivers/media/dvb/b2c2/flexcop-dma.c b/drivers/media/dvb/b2c2/flexcop-dma.c index 8d2706075360..cf4ed1df6086 100644 --- a/drivers/media/dvb/b2c2/flexcop-dma.c +++ b/drivers/media/dvb/b2c2/flexcop-dma.c | |||
@@ -37,22 +37,90 @@ void flexcop_dma_free(struct flexcop_dma *dma) | |||
37 | } | 37 | } |
38 | EXPORT_SYMBOL(flexcop_dma_free); | 38 | EXPORT_SYMBOL(flexcop_dma_free); |
39 | 39 | ||
40 | int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff) | 40 | int flexcop_dma_config(struct flexcop_device *fc, |
41 | struct flexcop_dma *dma, | ||
42 | flexcop_dma_index_t dma_idx) | ||
41 | { | 43 | { |
42 | flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); | 44 | flexcop_ibi_value v0x0,v0x4,v0xc; |
45 | v0x0.raw = v0x4.raw = v0xc.raw = 0; | ||
43 | 46 | ||
44 | if (no & FC_DMA_1) | 47 | v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2; |
45 | v.ctrl_208.DMA1_Timer_Enable_sig = onoff; | 48 | v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2; |
49 | v0x4.dma_0x4_write.dma_addr_size = dma->size / 4; | ||
46 | 50 | ||
47 | if (no & FC_DMA_2) | 51 | if ((dma_idx & FC_DMA_1) == dma_idx) { |
48 | v.ctrl_208.DMA2_Timer_Enable_sig = onoff; | 52 | fc->write_ibi_reg(fc,dma1_000,v0x0); |
53 | fc->write_ibi_reg(fc,dma1_004,v0x4); | ||
54 | fc->write_ibi_reg(fc,dma1_00c,v0xc); | ||
55 | } else if ((dma_idx & FC_DMA_2) == dma_idx) { | ||
56 | fc->write_ibi_reg(fc,dma2_010,v0x0); | ||
57 | fc->write_ibi_reg(fc,dma2_014,v0x4); | ||
58 | fc->write_ibi_reg(fc,dma2_01c,v0xc); | ||
59 | } else { | ||
60 | err("either DMA1 or DMA2 can be configured at the within one flexcop_dma_config call."); | ||
61 | return -EINVAL; | ||
62 | } | ||
49 | 63 | ||
50 | fc->write_ibi_reg(fc,ctrl_208,v); | ||
51 | return 0; | 64 | return 0; |
52 | } | 65 | } |
53 | EXPORT_SYMBOL(flexcop_dma_control_timer_irq); | 66 | EXPORT_SYMBOL(flexcop_dma_config); |
67 | |||
68 | /* start the DMA transfers, but not the DMA IRQs */ | ||
69 | int flexcop_dma_xfer_control(struct flexcop_device *fc, | ||
70 | flexcop_dma_index_t dma_idx, | ||
71 | flexcop_dma_addr_index_t index, | ||
72 | int onoff) | ||
73 | { | ||
74 | flexcop_ibi_value v0x0,v0xc; | ||
75 | flexcop_ibi_register r0x0,r0xc; | ||
76 | |||
77 | if ((dma_idx & FC_DMA_1) == dma_idx) { | ||
78 | r0x0 = dma1_000; | ||
79 | r0xc = dma1_00c; | ||
80 | } else if ((dma_idx & FC_DMA_2) == dma_idx) { | ||
81 | r0x0 = dma2_010; | ||
82 | r0xc = dma2_01c; | ||
83 | } else { | ||
84 | err("either transfer DMA1 or DMA2 can be started within one flexcop_dma_xfer_control call."); | ||
85 | return -EINVAL; | ||
86 | } | ||
87 | |||
88 | v0x0 = fc->read_ibi_reg(fc,r0x0); | ||
89 | v0xc = fc->read_ibi_reg(fc,r0xc); | ||
90 | |||
91 | deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw); | ||
92 | deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw); | ||
93 | |||
94 | if (index & FC_DMA_SUBADDR_0) | ||
95 | v0x0.dma_0x0.dma_0start = onoff; | ||
96 | |||
97 | if (index & FC_DMA_SUBADDR_1) | ||
98 | v0xc.dma_0xc.dma_1start = onoff; | ||
99 | |||
100 | fc->write_ibi_reg(fc,r0x0,v0x0); | ||
101 | fc->write_ibi_reg(fc,r0xc,v0xc); | ||
102 | |||
103 | deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw); | ||
104 | deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw); | ||
105 | return 0; | ||
106 | } | ||
107 | EXPORT_SYMBOL(flexcop_dma_xfer_control); | ||
108 | |||
109 | static int flexcop_dma_remap(struct flexcop_device *fc, | ||
110 | flexcop_dma_index_t dma_idx, | ||
111 | int onoff) | ||
112 | { | ||
113 | flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c; | ||
114 | flexcop_ibi_value v = fc->read_ibi_reg(fc,r); | ||
115 | deb_info("%s\n",__FUNCTION__); | ||
116 | v.dma_0xc.remap_enable = onoff; | ||
117 | fc->write_ibi_reg(fc,r,v); | ||
118 | return 0; | ||
119 | } | ||
54 | 120 | ||
55 | int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff) | 121 | int flexcop_dma_control_size_irq(struct flexcop_device *fc, |
122 | flexcop_dma_index_t no, | ||
123 | int onoff) | ||
56 | { | 124 | { |
57 | flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); | 125 | flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); |
58 | 126 | ||
@@ -67,75 +135,64 @@ int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t | |||
67 | } | 135 | } |
68 | EXPORT_SYMBOL(flexcop_dma_control_size_irq); | 136 | EXPORT_SYMBOL(flexcop_dma_control_size_irq); |
69 | 137 | ||
70 | int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff) | 138 | int flexcop_dma_control_timer_irq(struct flexcop_device *fc, |
139 | flexcop_dma_index_t no, | ||
140 | int onoff) | ||
71 | { | 141 | { |
72 | flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); | 142 | flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); |
73 | 143 | ||
74 | if (no & FC_DMA_1) | 144 | if (no & FC_DMA_1) |
75 | v.ctrl_208.DMA1_Size_IRQ_Enable_sig = onoff; | 145 | v.ctrl_208.DMA1_Timer_Enable_sig = onoff; |
76 | 146 | ||
77 | if (no & FC_DMA_2) | 147 | if (no & FC_DMA_2) |
78 | v.ctrl_208.DMA2_Size_IRQ_Enable_sig = onoff; | 148 | v.ctrl_208.DMA2_Timer_Enable_sig = onoff; |
79 | 149 | ||
80 | fc->write_ibi_reg(fc,ctrl_208,v); | 150 | fc->write_ibi_reg(fc,ctrl_208,v); |
81 | return 0; | 151 | return 0; |
82 | } | 152 | } |
83 | EXPORT_SYMBOL(flexcop_dma_control_packet_irq); | 153 | EXPORT_SYMBOL(flexcop_dma_control_timer_irq); |
84 | 154 | ||
85 | int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index) | 155 | /* 1 cycles = 1.97 msec */ |
156 | int flexcop_dma_config_timer(struct flexcop_device *fc, | ||
157 | flexcop_dma_index_t dma_idx, | ||
158 | u8 cycles) | ||
86 | { | 159 | { |
160 | flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014; | ||
161 | flexcop_ibi_value v = fc->read_ibi_reg(fc,r); | ||
87 | 162 | ||
88 | flexcop_ibi_value v0x0,v0x4,v0xc; | 163 | flexcop_dma_remap(fc,dma_idx,0); |
89 | v0x0.raw = v0x4.raw = v0xc.raw = 0; | ||
90 | |||
91 | v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2; | ||
92 | v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2; | ||
93 | v0x4.dma_0x4_write.dma_addr_size = dma->size / 4; | ||
94 | |||
95 | if (index & FC_DMA_SUBADDR_0) | ||
96 | v0x0.dma_0x0.dma_0start = 1; | ||
97 | |||
98 | if (index & FC_DMA_SUBADDR_1) | ||
99 | v0xc.dma_0xc.dma_1start = 1; | ||
100 | |||
101 | if (dma_idx & FC_DMA_1) { | ||
102 | fc->write_ibi_reg(fc,dma1_000,v0x0); | ||
103 | fc->write_ibi_reg(fc,dma1_004,v0x4); | ||
104 | fc->write_ibi_reg(fc,dma1_00c,v0xc); | ||
105 | } else { /* (dma_idx & FC_DMA_2) */ | ||
106 | fc->write_ibi_reg(fc,dma2_010,v0x0); | ||
107 | fc->write_ibi_reg(fc,dma2_014,v0x4); | ||
108 | fc->write_ibi_reg(fc,dma2_01c,v0xc); | ||
109 | } | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | EXPORT_SYMBOL(flexcop_dma_config); | ||
114 | 164 | ||
115 | static int flexcop_dma_remap(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, int onoff) | 165 | deb_info("%s\n",__FUNCTION__); |
116 | { | 166 | v.dma_0x4_write.dmatimer = cycles; |
117 | flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c; | ||
118 | flexcop_ibi_value v = fc->read_ibi_reg(fc,r); | ||
119 | v.dma_0xc.remap_enable = onoff; | ||
120 | fc->write_ibi_reg(fc,r,v); | 167 | fc->write_ibi_reg(fc,r,v); |
121 | return 0; | 168 | return 0; |
122 | } | 169 | } |
170 | EXPORT_SYMBOL(flexcop_dma_config_timer); | ||
123 | 171 | ||
124 | /* 1 cycles = 1.97 msec */ | 172 | /* packet IRQ does not exist in FCII or FCIIb - according to data book and tests */ |
125 | int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles) | 173 | int flexcop_dma_control_packet_irq(struct flexcop_device *fc, |
174 | flexcop_dma_index_t no, | ||
175 | int onoff) | ||
126 | { | 176 | { |
127 | flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014; | 177 | flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); |
128 | flexcop_ibi_value v = fc->read_ibi_reg(fc,r); | ||
129 | 178 | ||
130 | flexcop_dma_remap(fc,dma_idx,0); | 179 | deb_rdump("reg: %03x: %x\n",ctrl_208,v.raw); |
180 | if (no & FC_DMA_1) | ||
181 | v.ctrl_208.DMA1_Size_IRQ_Enable_sig = onoff; | ||
182 | |||
183 | if (no & FC_DMA_2) | ||
184 | v.ctrl_208.DMA2_Size_IRQ_Enable_sig = onoff; | ||
185 | |||
186 | fc->write_ibi_reg(fc,ctrl_208,v); | ||
187 | deb_rdump("reg: %03x: %x\n",ctrl_208,v.raw); | ||
131 | 188 | ||
132 | v.dma_0x4_write.dmatimer = cycles >> 1; | ||
133 | fc->write_ibi_reg(fc,r,v); | ||
134 | return 0; | 189 | return 0; |
135 | } | 190 | } |
136 | EXPORT_SYMBOL(flexcop_dma_config_timer); | 191 | EXPORT_SYMBOL(flexcop_dma_control_packet_irq); |
137 | 192 | ||
138 | int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets) | 193 | int flexcop_dma_config_packet_count(struct flexcop_device *fc, |
194 | flexcop_dma_index_t dma_idx, | ||
195 | u8 packets) | ||
139 | { | 196 | { |
140 | flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014; | 197 | flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014; |
141 | flexcop_ibi_value v = fc->read_ibi_reg(fc,r); | 198 | flexcop_ibi_value v = fc->read_ibi_reg(fc,r); |