1 /* 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> 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 21 #include <linux/kernel.h> 22 #include <linux/module.h> 23 #include <linux/videodev2.h> 24 #include <media/v4l2-ioctl.h> 25 26 #include "solo6x10.h" 27 28 #define SOLO_VCLK_DELAY 3 29 #define SOLO_PROGRESSIVE_VSIZE 1024 30 31 #define SOLO_MOT_THRESH_W 64 32 #define SOLO_MOT_THRESH_H 64 33 #define SOLO_MOT_THRESH_SIZE 8192 34 #define SOLO_MOT_THRESH_REAL (SOLO_MOT_THRESH_W * SOLO_MOT_THRESH_H) 35 #define SOLO_MOT_FLAG_SIZE 1024 36 #define SOLO_MOT_FLAG_AREA (SOLO_MOT_FLAG_SIZE * 16) 37 38 static void solo_vin_config(struct solo_dev *solo_dev) 39 { 40 solo_dev->vin_hstart = 8; 41 solo_dev->vin_vstart = 2; 42 43 solo_reg_write(solo_dev, SOLO_SYS_VCLK, 44 SOLO_VCLK_SELECT(2) | 45 SOLO_VCLK_VIN1415_DELAY(SOLO_VCLK_DELAY) | 46 SOLO_VCLK_VIN1213_DELAY(SOLO_VCLK_DELAY) | 47 SOLO_VCLK_VIN1011_DELAY(SOLO_VCLK_DELAY) | 48 SOLO_VCLK_VIN0809_DELAY(SOLO_VCLK_DELAY) | 49 SOLO_VCLK_VIN0607_DELAY(SOLO_VCLK_DELAY) | 50 SOLO_VCLK_VIN0405_DELAY(SOLO_VCLK_DELAY) | 51 SOLO_VCLK_VIN0203_DELAY(SOLO_VCLK_DELAY) | 52 SOLO_VCLK_VIN0001_DELAY(SOLO_VCLK_DELAY)); 53 54 solo_reg_write(solo_dev, SOLO_VI_ACT_I_P, 55 SOLO_VI_H_START(solo_dev->vin_hstart) | 56 SOLO_VI_V_START(solo_dev->vin_vstart) | 57 SOLO_VI_V_STOP(solo_dev->vin_vstart + 58 solo_dev->video_vsize)); 59 60 solo_reg_write(solo_dev, SOLO_VI_ACT_I_S, 61 SOLO_VI_H_START(solo_dev->vout_hstart) | 62 SOLO_VI_V_START(solo_dev->vout_vstart) | 63 SOLO_VI_V_STOP(solo_dev->vout_vstart + 64 solo_dev->video_vsize)); 65 66 solo_reg_write(solo_dev, SOLO_VI_ACT_P, 67 SOLO_VI_H_START(0) | 68 SOLO_VI_V_START(1) | 69 SOLO_VI_V_STOP(SOLO_PROGRESSIVE_VSIZE)); 70 71 solo_reg_write(solo_dev, SOLO_VI_CH_FORMAT, 72 SOLO_VI_FD_SEL_MASK(0) | SOLO_VI_PROG_MASK(0)); 73 74 /* On 6110, initialize mozaic darkness stength */ 75 if (solo_dev->type == SOLO_DEV_6010) 76 solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 0); 77 else 78 solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 16 << 22); 79 80 solo_reg_write(solo_dev, SOLO_VI_PAGE_SW, 2); 81 82 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { 83 solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG, 84 SOLO_VI_PB_USER_MODE); 85 solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV, 86 SOLO_VI_PB_HSIZE(858) | SOLO_VI_PB_VSIZE(246)); 87 solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V, 88 SOLO_VI_PB_VSTART(4) | 89 SOLO_VI_PB_VSTOP(4 + 240)); 90 } else { 91 solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG, 92 SOLO_VI_PB_USER_MODE | SOLO_VI_PB_PAL); 93 solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV, 94 SOLO_VI_PB_HSIZE(864) | SOLO_VI_PB_VSIZE(294)); 95 solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V, 96 SOLO_VI_PB_VSTART(4) | 97 SOLO_VI_PB_VSTOP(4 + 288)); 98 } 99 solo_reg_write(solo_dev, SOLO_VI_PB_ACT_H, SOLO_VI_PB_HSTART(16) | 100 SOLO_VI_PB_HSTOP(16 + 720)); 101 } 102 103 static void solo_vout_config_cursor(struct solo_dev *dev) 104 { 105 int i; 106 107 /* Load (blank) cursor bitmap mask (2bpp) */ 108 for (i = 0; i < 20; i++) 109 solo_reg_write(dev, SOLO_VO_CURSOR_MASK(i), 0); 110 111 solo_reg_write(dev, SOLO_VO_CURSOR_POS, 0); 112 113 solo_reg_write(dev, SOLO_VO_CURSOR_CLR, 114 (0x80 << 24) | (0x80 << 16) | (0x10 << 8) | 0x80); 115 solo_reg_write(dev, SOLO_VO_CURSOR_CLR2, (0xe0 << 8) | 0x80); 116 } 117 118 static void solo_vout_config(struct solo_dev *solo_dev) 119 { 120 solo_dev->vout_hstart = 6; 121 solo_dev->vout_vstart = 8; 122 123 solo_reg_write(solo_dev, SOLO_VO_FMT_ENC, 124 solo_dev->video_type | 125 SOLO_VO_USER_COLOR_SET_NAV | 126 SOLO_VO_USER_COLOR_SET_NAH | 127 SOLO_VO_NA_COLOR_Y(0) | 128 SOLO_VO_NA_COLOR_CB(0) | 129 SOLO_VO_NA_COLOR_CR(0)); 130 131 solo_reg_write(solo_dev, SOLO_VO_ACT_H, 132 SOLO_VO_H_START(solo_dev->vout_hstart) | 133 SOLO_VO_H_STOP(solo_dev->vout_hstart + 134 solo_dev->video_hsize)); 135 136 solo_reg_write(solo_dev, SOLO_VO_ACT_V, 137 SOLO_VO_V_START(solo_dev->vout_vstart) | 138 SOLO_VO_V_STOP(solo_dev->vout_vstart + 139 solo_dev->video_vsize)); 140 141 solo_reg_write(solo_dev, SOLO_VO_RANGE_HV, 142 SOLO_VO_H_LEN(solo_dev->video_hsize) | 143 SOLO_VO_V_LEN(solo_dev->video_vsize)); 144 145 /* Border & background colors */ 146 solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_COLOR, 147 (0xa0 << 24) | (0x88 << 16) | (0xa0 << 8) | 0x88); 148 solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_COLOR, 149 (0x10 << 24) | (0x8f << 16) | (0x10 << 8) | 0x8f); 150 solo_reg_write(solo_dev, SOLO_VO_BKG_COLOR, 151 (16 << 24) | (128 << 16) | (16 << 8) | 128); 152 153 solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON); 154 155 solo_reg_write(solo_dev, SOLO_VI_WIN_SW, 0); 156 157 solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0); 158 solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0); 159 160 solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, SOLO_VO_DISP_ON | 161 SOLO_VO_DISP_ERASE_COUNT(8) | 162 SOLO_VO_DISP_BASE(SOLO_DISP_EXT_ADDR)); 163 164 165 solo_vout_config_cursor(solo_dev); 166 167 /* Enable channels we support */ 168 solo_reg_write(solo_dev, SOLO_VI_CH_ENA, 169 (1 << solo_dev->nr_chans) - 1); 170 } 171 172 static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off, 173 u16 val, int reg_size) 174 { 175 __le16 *buf; 176 const int n = 64, size = n * sizeof(*buf); 177 int i, ret = 0; 178 179 buf = kmalloc(size, GFP_KERNEL); 180 if (!buf) 181 return -ENOMEM; 182 183 for (i = 0; i < n; i++) 184 buf[i] = cpu_to_le16(val); 185 186 for (i = 0; i < reg_size; i += size) { 187 ret = solo_p2m_dma(solo_dev, 1, buf, 188 SOLO_MOTION_EXT_ADDR(solo_dev) + off + i, 189 size, 0, 0); 190 191 if (ret) 192 break; 193 } 194 195 kfree(buf); 196 return ret; 197 } 198 199 int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val) 200 { 201 if (ch > solo_dev->nr_chans) 202 return -EINVAL; 203 204 return solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA + 205 (ch * SOLO_MOT_THRESH_SIZE * 2), 206 val, SOLO_MOT_THRESH_SIZE); 207 } 208 209 int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch, 210 const u16 *thresholds) 211 { 212 const unsigned size = sizeof(u16) * 64; 213 u32 off = SOLO_MOT_FLAG_AREA + ch * SOLO_MOT_THRESH_SIZE * 2; 214 __le16 *buf; 215 int x, y; 216 int ret = 0; 217 218 buf = kzalloc(size, GFP_KERNEL); 219 if (buf == NULL) 220 return -ENOMEM; 221 for (y = 0; y < SOLO_MOTION_SZ; y++) { 222 for (x = 0; x < SOLO_MOTION_SZ; x++) 223 buf[x] = cpu_to_le16(thresholds[y * SOLO_MOTION_SZ + x]); 224 ret |= solo_p2m_dma(solo_dev, 1, buf, 225 SOLO_MOTION_EXT_ADDR(solo_dev) + off + y * size, 226 size, 0, 0); 227 } 228 kfree(buf); 229 return ret; 230 } 231 232 /* First 8k is motion flag (512 bytes * 16). Following that is an 8k+8k 233 * threshold and working table for each channel. Atleast that's what the 234 * spec says. However, this code (taken from rdk) has some mystery 8k 235 * block right after the flag area, before the first thresh table. */ 236 static void solo_motion_config(struct solo_dev *solo_dev) 237 { 238 int i; 239 240 for (i = 0; i < solo_dev->nr_chans; i++) { 241 /* Clear motion flag area */ 242 solo_dma_vin_region(solo_dev, i * SOLO_MOT_FLAG_SIZE, 0x0000, 243 SOLO_MOT_FLAG_SIZE); 244 245 /* Clear working cache table */ 246 solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA + 247 (i * SOLO_MOT_THRESH_SIZE * 2) + 248 SOLO_MOT_THRESH_SIZE, 0x0000, 249 SOLO_MOT_THRESH_SIZE); 250 251 /* Set default threshold table */ 252 solo_set_motion_threshold(solo_dev, i, SOLO_DEF_MOT_THRESH); 253 } 254 255 /* Default motion settings */ 256 solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, SOLO_VI_MOTION_EN(0) | 257 (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16)); 258 solo_reg_write(solo_dev, SOLO_VI_MOT_CTRL, 259 SOLO_VI_MOTION_FRAME_COUNT(3) | 260 SOLO_VI_MOTION_SAMPLE_LENGTH(solo_dev->video_hsize / 16) 261 /* | SOLO_VI_MOTION_INTR_START_STOP */ 262 | SOLO_VI_MOTION_SAMPLE_COUNT(10)); 263 264 solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0); 265 solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0); 266 } 267 268 int solo_disp_init(struct solo_dev *solo_dev) 269 { 270 int i; 271 272 solo_dev->video_hsize = 704; 273 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { 274 solo_dev->video_vsize = 240; 275 solo_dev->fps = 30; 276 } else { 277 solo_dev->video_vsize = 288; 278 solo_dev->fps = 25; 279 } 280 281 solo_vin_config(solo_dev); 282 solo_motion_config(solo_dev); 283 solo_vout_config(solo_dev); 284 285 for (i = 0; i < solo_dev->nr_chans; i++) 286 solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 1); 287 288 return 0; 289 } 290 291 void solo_disp_exit(struct solo_dev *solo_dev) 292 { 293 int i; 294 295 solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, 0); 296 solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0); 297 solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0); 298 299 for (i = 0; i < solo_dev->nr_chans; i++) { 300 solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(i), 0); 301 solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(i), 0); 302 solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 0); 303 } 304 305 /* Set default border */ 306 for (i = 0; i < 5; i++) 307 solo_reg_write(solo_dev, SOLO_VO_BORDER_X(i), 0); 308 309 for (i = 0; i < 5; i++) 310 solo_reg_write(solo_dev, SOLO_VO_BORDER_Y(i), 0); 311 312 solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_MASK, 0); 313 solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_MASK, 0); 314 315 solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(0), 0); 316 solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(0), 0); 317 solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(0), 0); 318 319 solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(1), 0); 320 solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(1), 0); 321 solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(1), 0); 322 } 323