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#include <linux/slab.h> 22#include "solo6x10.h" 23#include "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 solo_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, SOLO_EOSD_EXT_ADDR >> 16); 97 solo_reg_write(solo_dev, SOLO_VE_OSD_CLR, 98 0xF0 << 16 | 0x80 << 8 | 0x80); 99 solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, 0); 100 101 /* Clear OSG buffer */ 102 buf = kzalloc(OSG_BUFFER_SIZE, GFP_KERNEL); 103 if (!buf) 104 return; 105 106 for (i = 0; i < solo_dev->nr_chans; i++) { 107 for (j = 0; j < SOLO_EOSD_EXT_SIZE; j += OSG_BUFFER_SIZE) { 108 solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_MP4E, 1, buf, 109 SOLO_EOSD_EXT_ADDR + 110 (i * SOLO_EOSD_EXT_SIZE) + j, 111 OSG_BUFFER_SIZE); 112 } 113 } 114 kfree(buf); 115} 116 117int solo_osd_print(struct solo_enc_dev *solo_enc) 118{ 119 struct solo_dev *solo_dev = solo_enc->solo_dev; 120 char *str = solo_enc->osd_text; 121 u8 *buf; 122 u32 reg = solo_reg_read(solo_dev, SOLO_VE_OSD_CH); 123 int len = strlen(str); 124 int i, j; 125 int x = 1, y = 1; 126 127 if (len == 0) { 128 reg &= ~(1 << solo_enc->ch); 129 solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg); 130 return 0; 131 } 132 133 buf = kzalloc(SOLO_EOSD_EXT_SIZE, GFP_KERNEL); 134 if (!buf) 135 return -ENOMEM; 136 137 for (i = 0; i < len; i++) { 138 for (j = 0; j < 16; j++) { 139 buf[(j*2) + (i%2) + ((x + (i/2)) * 32) + (y * 2048)] = 140 (solo_osd_font[(str[i] * 4) + (j / 4)] 141 >> ((3 - (j % 4)) * 8)) & 0xff; 142 } 143 } 144 145 solo_p2m_dma(solo_dev, 0, 1, buf, SOLO_EOSD_EXT_ADDR + 146 (solo_enc->ch * SOLO_EOSD_EXT_SIZE), SOLO_EOSD_EXT_SIZE); 147 reg |= (1 << solo_enc->ch); 148 solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg); 149 150 kfree(buf); 151 152 return 0; 153} 154 155static void solo_jpeg_config(struct solo_dev *solo_dev) 156{ 157 u32 reg; 158 if (solo_dev->flags & FLAGS_6110) 159 reg = (4 << 24) | (3 << 16) | (2 << 8) | (1 << 0); 160 else 161 reg = (2 << 24) | (2 << 16) | (2 << 8) | (2 << 0); 162 solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL, reg); 163 solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_L, 0); 164 solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_H, 0); 165 solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG, 166 (SOLO_JPEG_EXT_SIZE(solo_dev) & 0xffff0000) | 167 ((SOLO_JPEG_EXT_ADDR(solo_dev) >> 16) & 0x0000ffff)); 168 solo_reg_write(solo_dev, SOLO_VE_JPEG_CTRL, 0xffffffff); 169 /* que limit, samp limit, pos limit */ 170 solo_reg_write(solo_dev, 0x0688, (0 << 16) | (30 << 8) | 60); 171} 172 173static void solo_mp4e_config(struct solo_dev *solo_dev) 174{ 175 int i; 176 u32 reg; 177 178 /* We can only use VE_INTR_CTRL(0) if we want to support mjpeg */ 179 solo_reg_write(solo_dev, SOLO_VE_CFG0, 180 SOLO_VE_INTR_CTRL(0) | 181 SOLO_VE_BLOCK_SIZE(SOLO_MP4E_EXT_SIZE(solo_dev) >> 16) | 182 SOLO_VE_BLOCK_BASE(SOLO_MP4E_EXT_ADDR(solo_dev) >> 16)); 183 184 solo_reg_write(solo_dev, SOLO_VE_CFG1, 185 SOLO_VE_INSERT_INDEX | SOLO_VE_MOTION_MODE(0)); 186 187 solo_reg_write(solo_dev, SOLO_VE_WMRK_POLY, 0); 188 solo_reg_write(solo_dev, SOLO_VE_VMRK_INIT_KEY, 0); 189 solo_reg_write(solo_dev, SOLO_VE_WMRK_STRL, 0); 190 solo_reg_write(solo_dev, SOLO_VE_ENCRYP_POLY, 0); 191 solo_reg_write(solo_dev, SOLO_VE_ENCRYP_INIT, 0); 192 193 reg = SOLO_VE_LITTLE_ENDIAN | SOLO_COMP_ATTR_FCODE(1) | 194 SOLO_COMP_TIME_INC(0) | SOLO_COMP_TIME_WIDTH(15); 195 if (solo_dev->flags & FLAGS_6110) 196 reg |= SOLO_DCT_INTERVAL(10); 197 else 198 reg |= SOLO_DCT_INTERVAL(36 / 4); 199 solo_reg_write(solo_dev, SOLO_VE_ATTR, reg); 200 201 for (i = 0; i < solo_dev->nr_chans; i++) 202 solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE(i), 203 (SOLO_EREF_EXT_ADDR(solo_dev) + 204 (i * SOLO_EREF_EXT_SIZE)) >> 16); 205 206 if (solo_dev->flags & FLAGS_6110) 207 solo_reg_write(solo_dev, 0x0634, 0x00040008); /* ? */ 208} 209 210int solo_enc_init(struct solo_dev *solo_dev) 211{ 212 int i; 213 214 solo_capture_config(solo_dev); 215 solo_mp4e_config(solo_dev); 216 solo_jpeg_config(solo_dev); 217 218 for (i = 0; i < solo_dev->nr_chans; i++) { 219 solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0); 220 solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0); 221 } 222 223 solo_irq_on(solo_dev, SOLO_IRQ_ENCODER); 224 225 return 0; 226} 227 228void solo_enc_exit(struct solo_dev *solo_dev) 229{ 230 int i; 231 232 solo_irq_off(solo_dev, SOLO_IRQ_ENCODER); 233 234 for (i = 0; i < solo_dev->nr_chans; i++) { 235 solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0); 236 solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0); 237 } 238} 239