Commit | Line | Data |
---|---|---|
faa4fd2a | 1 | /* |
dcae5dac HV |
2 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> |
3 | * | |
4 | * Original author: | |
5 | * Ben Collins <bcollins@ubuntu.com> | |
6 | * | |
7 | * Additional work by: | |
8 | * John Brooks <john.brooks@bluecherry.net> | |
faa4fd2a BC |
9 | * |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License as published by | |
12 | * the Free Software Foundation; either version 2 of the License, or | |
13 | * (at your option) any later version. | |
14 | * | |
15 | * This program is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | * GNU General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU General Public License | |
21 | * along with this program; if not, write to the Free Software | |
22 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
23 | */ | |
24 | ||
25 | #include <linux/kernel.h> | |
26 | #include <linux/module.h> | |
27 | #include <linux/videodev2.h> | |
28 | #include <media/v4l2-ioctl.h> | |
dcae5dac | 29 | |
ae69b22c | 30 | #include "solo6x10.h" |
faa4fd2a BC |
31 | |
32 | #define SOLO_VCLK_DELAY 3 | |
33 | #define SOLO_PROGRESSIVE_VSIZE 1024 | |
34 | ||
35 | #define SOLO_MOT_THRESH_W 64 | |
36 | #define SOLO_MOT_THRESH_H 64 | |
37 | #define SOLO_MOT_THRESH_SIZE 8192 | |
38 | #define SOLO_MOT_THRESH_REAL (SOLO_MOT_THRESH_W * SOLO_MOT_THRESH_H) | |
dcae5dac HV |
39 | #define SOLO_MOT_FLAG_SIZE 1024 |
40 | #define SOLO_MOT_FLAG_AREA (SOLO_MOT_FLAG_SIZE * 16) | |
faa4fd2a | 41 | |
decebabf | 42 | static void solo_vin_config(struct solo_dev *solo_dev) |
faa4fd2a BC |
43 | { |
44 | solo_dev->vin_hstart = 8; | |
45 | solo_dev->vin_vstart = 2; | |
46 | ||
47 | solo_reg_write(solo_dev, SOLO_SYS_VCLK, | |
48 | SOLO_VCLK_SELECT(2) | | |
49 | SOLO_VCLK_VIN1415_DELAY(SOLO_VCLK_DELAY) | | |
50 | SOLO_VCLK_VIN1213_DELAY(SOLO_VCLK_DELAY) | | |
51 | SOLO_VCLK_VIN1011_DELAY(SOLO_VCLK_DELAY) | | |
52 | SOLO_VCLK_VIN0809_DELAY(SOLO_VCLK_DELAY) | | |
53 | SOLO_VCLK_VIN0607_DELAY(SOLO_VCLK_DELAY) | | |
54 | SOLO_VCLK_VIN0405_DELAY(SOLO_VCLK_DELAY) | | |
55 | SOLO_VCLK_VIN0203_DELAY(SOLO_VCLK_DELAY) | | |
56 | SOLO_VCLK_VIN0001_DELAY(SOLO_VCLK_DELAY)); | |
57 | ||
58 | solo_reg_write(solo_dev, SOLO_VI_ACT_I_P, | |
59 | SOLO_VI_H_START(solo_dev->vin_hstart) | | |
60 | SOLO_VI_V_START(solo_dev->vin_vstart) | | |
61 | SOLO_VI_V_STOP(solo_dev->vin_vstart + | |
62 | solo_dev->video_vsize)); | |
63 | ||
64 | solo_reg_write(solo_dev, SOLO_VI_ACT_I_S, | |
65 | SOLO_VI_H_START(solo_dev->vout_hstart) | | |
66 | SOLO_VI_V_START(solo_dev->vout_vstart) | | |
67 | SOLO_VI_V_STOP(solo_dev->vout_vstart + | |
68 | solo_dev->video_vsize)); | |
69 | ||
70 | solo_reg_write(solo_dev, SOLO_VI_ACT_P, | |
71 | SOLO_VI_H_START(0) | | |
72 | SOLO_VI_V_START(1) | | |
73 | SOLO_VI_V_STOP(SOLO_PROGRESSIVE_VSIZE)); | |
74 | ||
75 | solo_reg_write(solo_dev, SOLO_VI_CH_FORMAT, | |
76 | SOLO_VI_FD_SEL_MASK(0) | SOLO_VI_PROG_MASK(0)); | |
77 | ||
dcae5dac HV |
78 | /* On 6110, initialize mozaic darkness stength */ |
79 | if (solo_dev->type == SOLO_DEV_6010) | |
80 | solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 0); | |
81 | else | |
82 | solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 16 << 22); | |
83 | ||
faa4fd2a BC |
84 | solo_reg_write(solo_dev, SOLO_VI_PAGE_SW, 2); |
85 | ||
86 | if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { | |
87 | solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG, | |
88 | SOLO_VI_PB_USER_MODE); | |
89 | solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV, | |
90 | SOLO_VI_PB_HSIZE(858) | SOLO_VI_PB_VSIZE(246)); | |
91 | solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V, | |
92 | SOLO_VI_PB_VSTART(4) | | |
93 | SOLO_VI_PB_VSTOP(4 + 240)); | |
94 | } else { | |
95 | solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG, | |
96 | SOLO_VI_PB_USER_MODE | SOLO_VI_PB_PAL); | |
97 | solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV, | |
98 | SOLO_VI_PB_HSIZE(864) | SOLO_VI_PB_VSIZE(294)); | |
99 | solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V, | |
100 | SOLO_VI_PB_VSTART(4) | | |
101 | SOLO_VI_PB_VSTOP(4 + 288)); | |
102 | } | |
103 | solo_reg_write(solo_dev, SOLO_VI_PB_ACT_H, SOLO_VI_PB_HSTART(16) | | |
104 | SOLO_VI_PB_HSTOP(16 + 720)); | |
105 | } | |
106 | ||
dcae5dac HV |
107 | static void solo_vout_config_cursor(struct solo_dev *dev) |
108 | { | |
109 | int i; | |
110 | ||
111 | /* Load (blank) cursor bitmap mask (2bpp) */ | |
112 | for (i = 0; i < 20; i++) | |
113 | solo_reg_write(dev, SOLO_VO_CURSOR_MASK(i), 0); | |
114 | ||
115 | solo_reg_write(dev, SOLO_VO_CURSOR_POS, 0); | |
116 | ||
117 | solo_reg_write(dev, SOLO_VO_CURSOR_CLR, | |
118 | (0x80 << 24) | (0x80 << 16) | (0x10 << 8) | 0x80); | |
119 | solo_reg_write(dev, SOLO_VO_CURSOR_CLR2, (0xe0 << 8) | 0x80); | |
120 | } | |
121 | ||
122 | static void solo_vout_config(struct solo_dev *solo_dev) | |
faa4fd2a BC |
123 | { |
124 | solo_dev->vout_hstart = 6; | |
125 | solo_dev->vout_vstart = 8; | |
126 | ||
faa4fd2a BC |
127 | solo_reg_write(solo_dev, SOLO_VO_FMT_ENC, |
128 | solo_dev->video_type | | |
129 | SOLO_VO_USER_COLOR_SET_NAV | | |
dcae5dac | 130 | SOLO_VO_USER_COLOR_SET_NAH | |
faa4fd2a BC |
131 | SOLO_VO_NA_COLOR_Y(0) | |
132 | SOLO_VO_NA_COLOR_CB(0) | | |
133 | SOLO_VO_NA_COLOR_CR(0)); | |
134 | ||
135 | solo_reg_write(solo_dev, SOLO_VO_ACT_H, | |
136 | SOLO_VO_H_START(solo_dev->vout_hstart) | | |
137 | SOLO_VO_H_STOP(solo_dev->vout_hstart + | |
138 | solo_dev->video_hsize)); | |
139 | ||
140 | solo_reg_write(solo_dev, SOLO_VO_ACT_V, | |
141 | SOLO_VO_V_START(solo_dev->vout_vstart) | | |
142 | SOLO_VO_V_STOP(solo_dev->vout_vstart + | |
143 | solo_dev->video_vsize)); | |
144 | ||
145 | solo_reg_write(solo_dev, SOLO_VO_RANGE_HV, | |
146 | SOLO_VO_H_LEN(solo_dev->video_hsize) | | |
147 | SOLO_VO_V_LEN(solo_dev->video_vsize)); | |
148 | ||
dcae5dac HV |
149 | /* Border & background colors */ |
150 | solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_COLOR, | |
151 | (0xa0 << 24) | (0x88 << 16) | (0xa0 << 8) | 0x88); | |
152 | solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_COLOR, | |
153 | (0x10 << 24) | (0x8f << 16) | (0x10 << 8) | 0x8f); | |
154 | solo_reg_write(solo_dev, SOLO_VO_BKG_COLOR, | |
155 | (16 << 24) | (128 << 16) | (16 << 8) | 128); | |
156 | ||
157 | solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON); | |
158 | ||
159 | solo_reg_write(solo_dev, SOLO_VI_WIN_SW, 0); | |
160 | ||
161 | solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0); | |
162 | solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0); | |
faa4fd2a BC |
163 | |
164 | solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, SOLO_VO_DISP_ON | | |
165 | SOLO_VO_DISP_ERASE_COUNT(8) | | |
43d1136d | 166 | SOLO_VO_DISP_BASE(SOLO_DISP_EXT_ADDR)); |
faa4fd2a | 167 | |
faa4fd2a | 168 | |
dcae5dac | 169 | solo_vout_config_cursor(solo_dev); |
faa4fd2a | 170 | |
dcae5dac HV |
171 | /* Enable channels we support */ |
172 | solo_reg_write(solo_dev, SOLO_VI_CH_ENA, | |
173 | (1 << solo_dev->nr_chans) - 1); | |
faa4fd2a BC |
174 | } |
175 | ||
decebabf | 176 | static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off, |
faa4fd2a BC |
177 | u16 val, int reg_size) |
178 | { | |
179 | u16 buf[64]; | |
180 | int i; | |
181 | int ret = 0; | |
182 | ||
183 | for (i = 0; i < sizeof(buf) >> 1; i++) | |
22564285 | 184 | buf[i] = cpu_to_le16(val); |
faa4fd2a BC |
185 | |
186 | for (i = 0; i < reg_size; i += sizeof(buf)) | |
dcae5dac | 187 | ret |= solo_p2m_dma(solo_dev, 1, buf, |
faa4fd2a | 188 | SOLO_MOTION_EXT_ADDR(solo_dev) + off + i, |
dcae5dac | 189 | sizeof(buf), 0, 0); |
faa4fd2a BC |
190 | |
191 | return ret; | |
192 | } | |
193 | ||
dcae5dac | 194 | int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val) |
faa4fd2a BC |
195 | { |
196 | if (ch > solo_dev->nr_chans) | |
dcae5dac | 197 | return -EINVAL; |
faa4fd2a | 198 | |
dcae5dac HV |
199 | return solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA + |
200 | (ch * SOLO_MOT_THRESH_SIZE * 2), | |
201 | val, SOLO_MOT_THRESH_SIZE); | |
202 | } | |
203 | ||
f5df0b7f HV |
204 | int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch, |
205 | const struct solo_motion_thresholds *thresholds) | |
dcae5dac | 206 | { |
f5df0b7f | 207 | u32 off = SOLO_MOT_FLAG_AREA + ch * SOLO_MOT_THRESH_SIZE * 2; |
9e7664e0 | 208 | u16 buf[64]; |
f5df0b7f HV |
209 | int x, y; |
210 | int ret = 0; | |
dcae5dac | 211 | |
9e7664e0 | 212 | memset(buf, 0, sizeof(buf)); |
f5df0b7f HV |
213 | for (y = 0; y < SOLO_MOTION_SZ; y++) { |
214 | for (x = 0; x < SOLO_MOTION_SZ; x++) | |
215 | buf[x] = cpu_to_le16(thresholds->thresholds[y][x]); | |
216 | ret |= solo_p2m_dma(solo_dev, 1, buf, | |
217 | SOLO_MOTION_EXT_ADDR(solo_dev) + off + y * sizeof(buf), | |
218 | sizeof(buf), 0, 0); | |
219 | } | |
220 | return ret; | |
faa4fd2a BC |
221 | } |
222 | ||
223 | /* First 8k is motion flag (512 bytes * 16). Following that is an 8k+8k | |
224 | * threshold and working table for each channel. Atleast that's what the | |
dcae5dac | 225 | * spec says. However, this code (taken from rdk) has some mystery 8k |
faa4fd2a | 226 | * block right after the flag area, before the first thresh table. */ |
decebabf | 227 | static void solo_motion_config(struct solo_dev *solo_dev) |
faa4fd2a BC |
228 | { |
229 | int i; | |
230 | ||
231 | for (i = 0; i < solo_dev->nr_chans; i++) { | |
232 | /* Clear motion flag area */ | |
233 | solo_dma_vin_region(solo_dev, i * SOLO_MOT_FLAG_SIZE, 0x0000, | |
234 | SOLO_MOT_FLAG_SIZE); | |
235 | ||
236 | /* Clear working cache table */ | |
237 | solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA + | |
dcae5dac HV |
238 | (i * SOLO_MOT_THRESH_SIZE * 2) + |
239 | SOLO_MOT_THRESH_SIZE, 0x0000, | |
240 | SOLO_MOT_THRESH_SIZE); | |
faa4fd2a BC |
241 | |
242 | /* Set default threshold table */ | |
243 | solo_set_motion_threshold(solo_dev, i, SOLO_DEF_MOT_THRESH); | |
244 | } | |
245 | ||
246 | /* Default motion settings */ | |
f62de9be | 247 | solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, SOLO_VI_MOTION_EN(0) | |
faa4fd2a BC |
248 | (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16)); |
249 | solo_reg_write(solo_dev, SOLO_VI_MOT_CTRL, | |
250 | SOLO_VI_MOTION_FRAME_COUNT(3) | | |
251 | SOLO_VI_MOTION_SAMPLE_LENGTH(solo_dev->video_hsize / 16) | |
dcae5dac HV |
252 | /* | SOLO_VI_MOTION_INTR_START_STOP */ |
253 | | SOLO_VI_MOTION_SAMPLE_COUNT(10)); | |
faa4fd2a BC |
254 | |
255 | solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0); | |
256 | solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0); | |
257 | } | |
258 | ||
decebabf | 259 | int solo_disp_init(struct solo_dev *solo_dev) |
faa4fd2a BC |
260 | { |
261 | int i; | |
262 | ||
263 | solo_dev->video_hsize = 704; | |
4c211ed7 | 264 | if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { |
faa4fd2a BC |
265 | solo_dev->video_vsize = 240; |
266 | solo_dev->fps = 30; | |
267 | } else { | |
faa4fd2a BC |
268 | solo_dev->video_vsize = 288; |
269 | solo_dev->fps = 25; | |
270 | } | |
271 | ||
272 | solo_vin_config(solo_dev); | |
273 | solo_motion_config(solo_dev); | |
dcae5dac | 274 | solo_vout_config(solo_dev); |
faa4fd2a BC |
275 | |
276 | for (i = 0; i < solo_dev->nr_chans; i++) | |
277 | solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 1); | |
278 | ||
279 | return 0; | |
280 | } | |
281 | ||
decebabf | 282 | void solo_disp_exit(struct solo_dev *solo_dev) |
faa4fd2a BC |
283 | { |
284 | int i; | |
285 | ||
faa4fd2a BC |
286 | solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, 0); |
287 | solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0); | |
288 | solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0); | |
289 | ||
290 | for (i = 0; i < solo_dev->nr_chans; i++) { | |
291 | solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(i), 0); | |
292 | solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(i), 0); | |
293 | solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 0); | |
294 | } | |
295 | ||
296 | /* Set default border */ | |
297 | for (i = 0; i < 5; i++) | |
298 | solo_reg_write(solo_dev, SOLO_VO_BORDER_X(i), 0); | |
299 | ||
300 | for (i = 0; i < 5; i++) | |
301 | solo_reg_write(solo_dev, SOLO_VO_BORDER_Y(i), 0); | |
302 | ||
303 | solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_MASK, 0); | |
304 | solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_MASK, 0); | |
305 | ||
306 | solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(0), 0); | |
307 | solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(0), 0); | |
308 | solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(0), 0); | |
afabbe6d | 309 | |
faa4fd2a BC |
310 | solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(1), 0); |
311 | solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(1), 0); | |
312 | solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(1), 0); | |
313 | } |