solo6x10-enc.c (8975B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com> 4 * 5 * Original author: 6 * Ben Collins <bcollins@ubuntu.com> 7 * 8 * Additional work by: 9 * John Brooks <john.brooks@bluecherry.net> 10 */ 11 12#include <linux/kernel.h> 13#include <linux/font.h> 14#include <linux/bitrev.h> 15#include <linux/slab.h> 16 17#include "solo6x10.h" 18 19#define VI_PROG_HSIZE (1280 - 16) 20#define VI_PROG_VSIZE (1024 - 16) 21 22#define IRQ_LEVEL 2 23 24static void solo_capture_config(struct solo_dev *solo_dev) 25{ 26 unsigned long height; 27 unsigned long width; 28 void *buf; 29 int i; 30 31 solo_reg_write(solo_dev, SOLO_CAP_BASE, 32 SOLO_CAP_MAX_PAGE((SOLO_CAP_EXT_SIZE(solo_dev) 33 - SOLO_CAP_PAGE_SIZE) >> 16) 34 | SOLO_CAP_BASE_ADDR(SOLO_CAP_EXT_ADDR(solo_dev) >> 16)); 35 36 /* XXX: Undocumented bits at b17 and b24 */ 37 if (solo_dev->type == SOLO_DEV_6110) { 38 /* NOTE: Ref driver has (62 << 24) here as well, but it causes 39 * wacked out frame timing on 4-port 6110. */ 40 solo_reg_write(solo_dev, SOLO_CAP_BTW, 41 (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) | 42 SOLO_CAP_MAX_BANDWIDTH(36)); 43 } else { 44 solo_reg_write(solo_dev, SOLO_CAP_BTW, 45 (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) | 46 SOLO_CAP_MAX_BANDWIDTH(32)); 47 } 48 49 /* Set scale 1, 9 dimension */ 50 width = solo_dev->video_hsize; 51 height = solo_dev->video_vsize; 52 solo_reg_write(solo_dev, SOLO_DIM_SCALE1, 53 SOLO_DIM_H_MB_NUM(width / 16) | 54 SOLO_DIM_V_MB_NUM_FRAME(height / 8) | 55 SOLO_DIM_V_MB_NUM_FIELD(height / 16)); 56 57 /* Set scale 2, 10 dimension */ 58 width = solo_dev->video_hsize / 2; 59 height = solo_dev->video_vsize; 60 solo_reg_write(solo_dev, SOLO_DIM_SCALE2, 61 SOLO_DIM_H_MB_NUM(width / 16) | 62 SOLO_DIM_V_MB_NUM_FRAME(height / 8) | 63 SOLO_DIM_V_MB_NUM_FIELD(height / 16)); 64 65 /* Set scale 3, 11 dimension */ 66 width = solo_dev->video_hsize / 2; 67 height = solo_dev->video_vsize / 2; 68 solo_reg_write(solo_dev, SOLO_DIM_SCALE3, 69 SOLO_DIM_H_MB_NUM(width / 16) | 70 SOLO_DIM_V_MB_NUM_FRAME(height / 8) | 71 SOLO_DIM_V_MB_NUM_FIELD(height / 16)); 72 73 /* Set scale 4, 12 dimension */ 74 width = solo_dev->video_hsize / 3; 75 height = solo_dev->video_vsize / 3; 76 solo_reg_write(solo_dev, SOLO_DIM_SCALE4, 77 SOLO_DIM_H_MB_NUM(width / 16) | 78 SOLO_DIM_V_MB_NUM_FRAME(height / 8) | 79 SOLO_DIM_V_MB_NUM_FIELD(height / 16)); 80 81 /* Set scale 5, 13 dimension */ 82 width = solo_dev->video_hsize / 4; 83 height = solo_dev->video_vsize / 2; 84 solo_reg_write(solo_dev, SOLO_DIM_SCALE5, 85 SOLO_DIM_H_MB_NUM(width / 16) | 86 SOLO_DIM_V_MB_NUM_FRAME(height / 8) | 87 SOLO_DIM_V_MB_NUM_FIELD(height / 16)); 88 89 /* Progressive */ 90 width = VI_PROG_HSIZE; 91 height = VI_PROG_VSIZE; 92 solo_reg_write(solo_dev, SOLO_DIM_PROG, 93 SOLO_DIM_H_MB_NUM(width / 16) | 94 SOLO_DIM_V_MB_NUM_FRAME(height / 16) | 95 SOLO_DIM_V_MB_NUM_FIELD(height / 16)); 96 97 /* Clear OSD */ 98 solo_reg_write(solo_dev, SOLO_VE_OSD_CH, 0); 99 solo_reg_write(solo_dev, SOLO_VE_OSD_BASE, SOLO_EOSD_EXT_ADDR >> 16); 100 solo_reg_write(solo_dev, SOLO_VE_OSD_CLR, 101 0xF0 << 16 | 0x80 << 8 | 0x80); 102 103 if (solo_dev->type == SOLO_DEV_6010) 104 solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, 105 SOLO_VE_OSD_H_SHADOW | SOLO_VE_OSD_V_SHADOW); 106 else 107 solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, SOLO_VE_OSD_V_DOUBLE 108 | SOLO_VE_OSD_H_SHADOW | SOLO_VE_OSD_V_SHADOW); 109 110 /* Clear OSG buffer */ 111 buf = kzalloc(SOLO_EOSD_EXT_SIZE(solo_dev), GFP_KERNEL); 112 if (!buf) 113 return; 114 115 for (i = 0; i < solo_dev->nr_chans; i++) { 116 solo_p2m_dma(solo_dev, 1, buf, 117 SOLO_EOSD_EXT_ADDR + 118 (SOLO_EOSD_EXT_SIZE(solo_dev) * i), 119 SOLO_EOSD_EXT_SIZE(solo_dev), 0, 0); 120 } 121 kfree(buf); 122} 123 124#define SOLO_OSD_WRITE_SIZE (16 * OSD_TEXT_MAX) 125 126/* Should be called with enable_lock held */ 127int solo_osd_print(struct solo_enc_dev *solo_enc) 128{ 129 struct solo_dev *solo_dev = solo_enc->solo_dev; 130 u8 *str = solo_enc->osd_text; 131 u8 *buf = solo_enc->osd_buf; 132 u32 reg; 133 const struct font_desc *vga = find_font("VGA8x16"); 134 const u8 *vga_data; 135 int i, j; 136 137 if (WARN_ON_ONCE(!vga)) 138 return -ENODEV; 139 140 reg = solo_reg_read(solo_dev, SOLO_VE_OSD_CH); 141 if (!*str) { 142 /* Disable OSD on this channel */ 143 reg &= ~(1 << solo_enc->ch); 144 goto out; 145 } 146 147 memset(buf, 0, SOLO_OSD_WRITE_SIZE); 148 vga_data = (const u8 *)vga->data; 149 150 for (i = 0; *str; i++, str++) { 151 for (j = 0; j < 16; j++) { 152 buf[(j << 1) | (i & 1) | ((i & ~1) << 4)] = 153 bitrev8(vga_data[(*str << 4) | j]); 154 } 155 } 156 157 solo_p2m_dma(solo_dev, 1, buf, 158 SOLO_EOSD_EXT_ADDR_CHAN(solo_dev, solo_enc->ch), 159 SOLO_OSD_WRITE_SIZE, 0, 0); 160 161 /* Enable OSD on this channel */ 162 reg |= (1 << solo_enc->ch); 163 164out: 165 solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg); 166 return 0; 167} 168 169/* 170 * Set channel Quality Profile (0-3). 171 */ 172void solo_s_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch, 173 unsigned int qp) 174{ 175 unsigned long flags; 176 unsigned int idx, reg; 177 178 if ((ch > 31) || (qp > 3)) 179 return; 180 181 if (solo_dev->type == SOLO_DEV_6010) 182 return; 183 184 if (ch < 16) { 185 idx = 0; 186 reg = SOLO_VE_JPEG_QP_CH_L; 187 } else { 188 ch -= 16; 189 idx = 1; 190 reg = SOLO_VE_JPEG_QP_CH_H; 191 } 192 ch *= 2; 193 194 spin_lock_irqsave(&solo_dev->jpeg_qp_lock, flags); 195 196 solo_dev->jpeg_qp[idx] &= ~(3 << ch); 197 solo_dev->jpeg_qp[idx] |= (qp & 3) << ch; 198 199 solo_reg_write(solo_dev, reg, solo_dev->jpeg_qp[idx]); 200 201 spin_unlock_irqrestore(&solo_dev->jpeg_qp_lock, flags); 202} 203 204int solo_g_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch) 205{ 206 int idx; 207 208 if (solo_dev->type == SOLO_DEV_6010) 209 return 2; 210 211 if (WARN_ON_ONCE(ch > 31)) 212 return 2; 213 214 if (ch < 16) { 215 idx = 0; 216 } else { 217 ch -= 16; 218 idx = 1; 219 } 220 ch *= 2; 221 222 return (solo_dev->jpeg_qp[idx] >> ch) & 3; 223} 224 225#define SOLO_QP_INIT 0xaaaaaaaa 226 227static void solo_jpeg_config(struct solo_dev *solo_dev) 228{ 229 if (solo_dev->type == SOLO_DEV_6010) { 230 solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL, 231 (2 << 24) | (2 << 16) | (2 << 8) | 2); 232 } else { 233 solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL, 234 (4 << 24) | (3 << 16) | (2 << 8) | 1); 235 } 236 237 spin_lock_init(&solo_dev->jpeg_qp_lock); 238 239 /* Initialize Quality Profile for all channels */ 240 solo_dev->jpeg_qp[0] = solo_dev->jpeg_qp[1] = SOLO_QP_INIT; 241 solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_L, SOLO_QP_INIT); 242 solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_H, SOLO_QP_INIT); 243 244 solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG, 245 (SOLO_JPEG_EXT_SIZE(solo_dev) & 0xffff0000) | 246 ((SOLO_JPEG_EXT_ADDR(solo_dev) >> 16) & 0x0000ffff)); 247 solo_reg_write(solo_dev, SOLO_VE_JPEG_CTRL, 0xffffffff); 248 if (solo_dev->type == SOLO_DEV_6110) { 249 solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG1, 250 (0 << 16) | (30 << 8) | 60); 251 } 252} 253 254static void solo_mp4e_config(struct solo_dev *solo_dev) 255{ 256 int i; 257 u32 cfg; 258 259 solo_reg_write(solo_dev, SOLO_VE_CFG0, 260 SOLO_VE_INTR_CTRL(IRQ_LEVEL) | 261 SOLO_VE_BLOCK_SIZE(SOLO_MP4E_EXT_SIZE(solo_dev) >> 16) | 262 SOLO_VE_BLOCK_BASE(SOLO_MP4E_EXT_ADDR(solo_dev) >> 16)); 263 264 265 cfg = SOLO_VE_BYTE_ALIGN(2) | SOLO_VE_INSERT_INDEX 266 | SOLO_VE_MOTION_MODE(0); 267 if (solo_dev->type != SOLO_DEV_6010) { 268 cfg |= SOLO_VE_MPEG_SIZE_H( 269 (SOLO_MP4E_EXT_SIZE(solo_dev) >> 24) & 0x0f); 270 cfg |= SOLO_VE_JPEG_SIZE_H( 271 (SOLO_JPEG_EXT_SIZE(solo_dev) >> 24) & 0x0f); 272 } 273 solo_reg_write(solo_dev, SOLO_VE_CFG1, cfg); 274 275 solo_reg_write(solo_dev, SOLO_VE_WMRK_POLY, 0); 276 solo_reg_write(solo_dev, SOLO_VE_VMRK_INIT_KEY, 0); 277 solo_reg_write(solo_dev, SOLO_VE_WMRK_STRL, 0); 278 if (solo_dev->type == SOLO_DEV_6110) 279 solo_reg_write(solo_dev, SOLO_VE_WMRK_ENABLE, 0); 280 solo_reg_write(solo_dev, SOLO_VE_ENCRYP_POLY, 0); 281 solo_reg_write(solo_dev, SOLO_VE_ENCRYP_INIT, 0); 282 283 solo_reg_write(solo_dev, SOLO_VE_ATTR, 284 SOLO_VE_LITTLE_ENDIAN | 285 SOLO_COMP_ATTR_FCODE(1) | 286 SOLO_COMP_TIME_INC(0) | 287 SOLO_COMP_TIME_WIDTH(15) | 288 SOLO_DCT_INTERVAL(solo_dev->type == SOLO_DEV_6010 ? 9 : 10)); 289 290 for (i = 0; i < solo_dev->nr_chans; i++) { 291 solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE(i), 292 (SOLO_EREF_EXT_ADDR(solo_dev) + 293 (i * SOLO_EREF_EXT_SIZE)) >> 16); 294 solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE_E(i), 295 (SOLO_EREF_EXT_ADDR(solo_dev) + 296 ((i + 16) * SOLO_EREF_EXT_SIZE)) >> 16); 297 } 298 299 if (solo_dev->type == SOLO_DEV_6110) { 300 solo_reg_write(solo_dev, SOLO_VE_COMPT_MOT, 0x00040008); 301 } else { 302 for (i = 0; i < solo_dev->nr_chans; i++) 303 solo_reg_write(solo_dev, SOLO_VE_CH_MOT(i), 0x100); 304 } 305} 306 307int solo_enc_init(struct solo_dev *solo_dev) 308{ 309 int i; 310 311 solo_capture_config(solo_dev); 312 solo_mp4e_config(solo_dev); 313 solo_jpeg_config(solo_dev); 314 315 for (i = 0; i < solo_dev->nr_chans; i++) { 316 solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0); 317 solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0); 318 } 319 320 return 0; 321} 322 323void solo_enc_exit(struct solo_dev *solo_dev) 324{ 325 int i; 326 327 for (i = 0; i < solo_dev->nr_chans; i++) { 328 solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0); 329 solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0); 330 } 331}