1/* 2 * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com 3 * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 */ 19 20#include <linux/kernel.h> 21 22#include "solo6010.h" 23#include "solo6010-osd-font.h" 24 25#define CAPTURE_MAX_BANDWIDTH 32 // D1 4channel (D1 == 4) 26#define OSG_BUFFER_SIZE 1024 27 28#define VI_PROG_HSIZE (1280 - 16) 29#define VI_PROG_VSIZE (1024 - 16) 30 31static void solo_capture_config(struct solo6010_dev *solo_dev) 32{ 33 int i, j; 34 unsigned long height; 35 unsigned long width; 36 unsigned char *buf; 37 38 solo_reg_write(solo_dev, SOLO_CAP_BASE, 39 SOLO_CAP_MAX_PAGE(SOLO_CAP_EXT_MAX_PAGE * 40 solo_dev->nr_chans) | 41 SOLO_CAP_BASE_ADDR(SOLO_CAP_EXT_ADDR(solo_dev) >> 16)); 42 solo_reg_write(solo_dev, SOLO_CAP_BTW, 43 (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) | 44 SOLO_CAP_MAX_BANDWIDTH(CAPTURE_MAX_BANDWIDTH)); 45 46 /* Set scale 1, 9 dimension */ 47 width = solo_dev->video_hsize; 48 height = solo_dev->video_vsize; 49 solo_reg_write(solo_dev, SOLO_DIM_SCALE1, 50 SOLO_DIM_H_MB_NUM(width / 16) | 51 SOLO_DIM_V_MB_NUM_FRAME(height / 8) | 52 SOLO_DIM_V_MB_NUM_FIELD(height / 16)); 53 54 /* Set scale 2, 10 dimension */ 55 width = solo_dev->video_hsize / 2; 56 height = solo_dev->video_vsize; 57 solo_reg_write(solo_dev, SOLO_DIM_SCALE2, 58 SOLO_DIM_H_MB_NUM(width / 16) | 59 SOLO_DIM_V_MB_NUM_FRAME(height / 8) | 60 SOLO_DIM_V_MB_NUM_FIELD(height / 16)); 61 62 /* Set scale 3, 11 dimension */ 63 width = solo_dev->video_hsize / 2; 64 height = solo_dev->video_vsize / 2; 65 solo_reg_write(solo_dev, SOLO_DIM_SCALE3, 66 SOLO_DIM_H_MB_NUM(width / 16) | 67 SOLO_DIM_V_MB_NUM_FRAME(height / 8) | 68 SOLO_DIM_V_MB_NUM_FIELD(height / 16)); 69 70 /* Set scale 4, 12 dimension */ 71 width = solo_dev->video_hsize / 3; 72 height = solo_dev->video_vsize / 3; 73 solo_reg_write(solo_dev, SOLO_DIM_SCALE4, 74 SOLO_DIM_H_MB_NUM(width / 16) | 75 SOLO_DIM_V_MB_NUM_FRAME(height / 8) | 76 SOLO_DIM_V_MB_NUM_FIELD(height / 16)); 77 78 /* Set scale 5, 13 dimension */ 79 width = solo_dev->video_hsize / 4; 80 height = solo_dev->video_vsize / 2; 81 solo_reg_write(solo_dev, SOLO_DIM_SCALE5, 82 SOLO_DIM_H_MB_NUM(width / 16) | 83 SOLO_DIM_V_MB_NUM_FRAME(height / 8) | 84 SOLO_DIM_V_MB_NUM_FIELD(height / 16)); 85 86 /* Progressive */ 87 width = VI_PROG_HSIZE; 88 height = VI_PROG_VSIZE; 89 solo_reg_write(solo_dev, SOLO_DIM_PROG, 90 SOLO_DIM_H_MB_NUM(width / 16) | 91 SOLO_DIM_V_MB_NUM_FRAME(height / 16) | 92 SOLO_DIM_V_MB_NUM_FIELD(height / 16)); 93 94 /* Clear OSD */ 95 solo_reg_write(solo_dev, SOLO_VE_OSD_CH, 0); 96 solo_reg_write(solo_dev, SOLO_VE_OSD_BASE, 97 SOLO_EOSD_EXT_ADDR(solo_dev) >> 16); 98 solo_reg_write(solo_dev, SOLO_VE_OSD_CLR, 99 0xF0 << 16 | 0x80 << 8 | 0x80); 100 solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, 0); 101 102 /* Clear OSG buffer */ 103 buf = kzalloc(OSG_BUFFER_SIZE, GFP_KERNEL); 104 if (!buf) 105 return; 106 107 for (i = 0; i < solo_dev->nr_chans; i++) { 108 for (j = 0; j < SOLO_EOSD_EXT_SIZE; j += OSG_BUFFER_SIZE) { 109 solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_MP4E, 1, buf, 110 SOLO_EOSD_EXT_ADDR(solo_dev) + 111 (i * SOLO_EOSD_EXT_SIZE) + j, 112 OSG_BUFFER_SIZE); 113 } 114 } 115 kfree(buf); 116} 117 118int solo_osd_print(struct solo_enc_dev *solo_enc) 119{ 120 struct solo6010_dev *solo_dev = solo_enc->solo_dev; 121 char *str = solo_enc->osd_text; 122 u8 *buf; 123 u32 reg = solo_reg_read(solo_dev, SOLO_VE_OSD_CH); 124 int len = strlen(str); 125 int i, j; 126 int x = 1, y = 1; 127 128 if (len == 0) { 129 reg &= ~(1 << solo_enc->ch); 130 solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg); 131 return 0; 132 } 133 134 buf = kzalloc(SOLO_EOSD_EXT_SIZE, GFP_KERNEL); 135 if (!buf) 136 return -ENOMEM; 137 138 for (i = 0; i < len; i++) { 139 for (j = 0; j < 16; j++) { 140 buf[(j*2) + (i%2) + ((x + (i/2)) * 32) + (y * 2048)] = 141 (solo_osd_font[(str[i] * 4) + (j / 4)] 142 >> ((3 - (j % 4)) * 8)) & 0xff; 143 } 144 } 145 146 solo_p2m_dma(solo_dev, 0, 1, buf, SOLO_EOSD_EXT_ADDR(solo_dev) + 147 (solo_enc->ch * SOLO_EOSD_EXT_SIZE), SOLO_EOSD_EXT_SIZE); 148 reg |= (1 << solo_enc->ch); 149 solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg); 150 151 kfree(buf); 152 153 return 0; 154} 155 156static void solo_jpeg_config(struct solo6010_dev *solo_dev) 157{ 158 solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL, 159 (2 << 24) | (2 << 16) | (2 << 8) | (2 << 0)); 160 solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_L, 0); 161 solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_H, 0); 162 solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG, 163 (SOLO_JPEG_EXT_SIZE(solo_dev) & 0xffff0000) | 164 ((SOLO_JPEG_EXT_ADDR(solo_dev) >> 16) & 0x0000ffff)); 165 solo_reg_write(solo_dev, SOLO_VE_JPEG_CTRL, 0xffffffff); 166} 167 168static void solo_mp4e_config(struct solo6010_dev *solo_dev) 169{ 170 int i; 171 172 /* We can only use VE_INTR_CTRL(0) if we want to support mjpeg */ 173 solo_reg_write(solo_dev, SOLO_VE_CFG0, 174 SOLO_VE_INTR_CTRL(0) | 175 SOLO_VE_BLOCK_SIZE(SOLO_MP4E_EXT_SIZE(solo_dev) >> 16) | 176 SOLO_VE_BLOCK_BASE(SOLO_MP4E_EXT_ADDR(solo_dev) >> 16)); 177 178 solo_reg_write(solo_dev, SOLO_VE_CFG1, 179 SOLO_VE_BYTE_ALIGN(2) | 180 SOLO_VE_INSERT_INDEX | SOLO_VE_MOTION_MODE(0)); 181 182 solo_reg_write(solo_dev, SOLO_VE_WMRK_POLY, 0); 183 solo_reg_write(solo_dev, SOLO_VE_VMRK_INIT_KEY, 0); 184 solo_reg_write(solo_dev, SOLO_VE_WMRK_STRL, 0); 185 solo_reg_write(solo_dev, SOLO_VE_ENCRYP_POLY, 0); 186 solo_reg_write(solo_dev, SOLO_VE_ENCRYP_INIT, 0); 187 188 solo_reg_write(solo_dev, SOLO_VE_ATTR, 189 SOLO_VE_LITTLE_ENDIAN | 190 SOLO_COMP_ATTR_FCODE(1) | 191 SOLO_COMP_TIME_INC(0) | 192 SOLO_COMP_TIME_WIDTH(15) | 193 SOLO_DCT_INTERVAL(36 / 4)); 194 195 for (i = 0; i < solo_dev->nr_chans; i++) 196 solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE(i), 197 (SOLO_EREF_EXT_ADDR(solo_dev) + 198 (i * SOLO_EREF_EXT_SIZE)) >> 16); 199} 200 201int solo_enc_init(struct solo6010_dev *solo_dev) 202{ 203 int i; 204 205 solo_capture_config(solo_dev); 206 solo_mp4e_config(solo_dev); 207 solo_jpeg_config(solo_dev); 208 209 for (i = 0; i < solo_dev->nr_chans; i++) { 210 solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0); 211 solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0); 212 } 213 214 solo6010_irq_on(solo_dev, SOLO_IRQ_ENCODER); 215 216 return 0; 217} 218 219void solo_enc_exit(struct solo6010_dev *solo_dev) 220{ 221 int i; 222 223 solo6010_irq_off(solo_dev, SOLO_IRQ_ENCODER); 224 225 for (i = 0; i < solo_dev->nr_chans; i++) { 226 solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0); 227 solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0); 228 } 229} 230