1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 228cae868SHans Verkuil /* 328cae868SHans Verkuil * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> 428cae868SHans Verkuil * 528cae868SHans Verkuil * Original author: 628cae868SHans Verkuil * Ben Collins <bcollins@ubuntu.com> 728cae868SHans Verkuil * 828cae868SHans Verkuil * Additional work by: 928cae868SHans Verkuil * John Brooks <john.brooks@bluecherry.net> 1028cae868SHans Verkuil */ 1128cae868SHans Verkuil 1228cae868SHans Verkuil #include <linux/kernel.h> 1328cae868SHans Verkuil #include <linux/font.h> 1428cae868SHans Verkuil #include <linux/bitrev.h> 1528cae868SHans Verkuil #include <linux/slab.h> 1628cae868SHans Verkuil 1728cae868SHans Verkuil #include "solo6x10.h" 1828cae868SHans Verkuil 1928cae868SHans Verkuil #define VI_PROG_HSIZE (1280 - 16) 2028cae868SHans Verkuil #define VI_PROG_VSIZE (1024 - 16) 2128cae868SHans Verkuil 2228cae868SHans Verkuil #define IRQ_LEVEL 2 2328cae868SHans Verkuil 2428cae868SHans Verkuil static void solo_capture_config(struct solo_dev *solo_dev) 2528cae868SHans Verkuil { 2628cae868SHans Verkuil unsigned long height; 2728cae868SHans Verkuil unsigned long width; 2828cae868SHans Verkuil void *buf; 2928cae868SHans Verkuil int i; 3028cae868SHans Verkuil 3128cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_CAP_BASE, 3228cae868SHans Verkuil SOLO_CAP_MAX_PAGE((SOLO_CAP_EXT_SIZE(solo_dev) 3328cae868SHans Verkuil - SOLO_CAP_PAGE_SIZE) >> 16) 3428cae868SHans Verkuil | SOLO_CAP_BASE_ADDR(SOLO_CAP_EXT_ADDR(solo_dev) >> 16)); 3528cae868SHans Verkuil 3628cae868SHans Verkuil /* XXX: Undocumented bits at b17 and b24 */ 3728cae868SHans Verkuil if (solo_dev->type == SOLO_DEV_6110) { 3828cae868SHans Verkuil /* NOTE: Ref driver has (62 << 24) here as well, but it causes 3928cae868SHans Verkuil * wacked out frame timing on 4-port 6110. */ 4028cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_CAP_BTW, 4128cae868SHans Verkuil (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) | 4228cae868SHans Verkuil SOLO_CAP_MAX_BANDWIDTH(36)); 4328cae868SHans Verkuil } else { 4428cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_CAP_BTW, 4528cae868SHans Verkuil (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) | 4628cae868SHans Verkuil SOLO_CAP_MAX_BANDWIDTH(32)); 4728cae868SHans Verkuil } 4828cae868SHans Verkuil 4928cae868SHans Verkuil /* Set scale 1, 9 dimension */ 5028cae868SHans Verkuil width = solo_dev->video_hsize; 5128cae868SHans Verkuil height = solo_dev->video_vsize; 5228cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_DIM_SCALE1, 5328cae868SHans Verkuil SOLO_DIM_H_MB_NUM(width / 16) | 5428cae868SHans Verkuil SOLO_DIM_V_MB_NUM_FRAME(height / 8) | 5528cae868SHans Verkuil SOLO_DIM_V_MB_NUM_FIELD(height / 16)); 5628cae868SHans Verkuil 5728cae868SHans Verkuil /* Set scale 2, 10 dimension */ 5828cae868SHans Verkuil width = solo_dev->video_hsize / 2; 5928cae868SHans Verkuil height = solo_dev->video_vsize; 6028cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_DIM_SCALE2, 6128cae868SHans Verkuil SOLO_DIM_H_MB_NUM(width / 16) | 6228cae868SHans Verkuil SOLO_DIM_V_MB_NUM_FRAME(height / 8) | 6328cae868SHans Verkuil SOLO_DIM_V_MB_NUM_FIELD(height / 16)); 6428cae868SHans Verkuil 6528cae868SHans Verkuil /* Set scale 3, 11 dimension */ 6628cae868SHans Verkuil width = solo_dev->video_hsize / 2; 6728cae868SHans Verkuil height = solo_dev->video_vsize / 2; 6828cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_DIM_SCALE3, 6928cae868SHans Verkuil SOLO_DIM_H_MB_NUM(width / 16) | 7028cae868SHans Verkuil SOLO_DIM_V_MB_NUM_FRAME(height / 8) | 7128cae868SHans Verkuil SOLO_DIM_V_MB_NUM_FIELD(height / 16)); 7228cae868SHans Verkuil 7328cae868SHans Verkuil /* Set scale 4, 12 dimension */ 7428cae868SHans Verkuil width = solo_dev->video_hsize / 3; 7528cae868SHans Verkuil height = solo_dev->video_vsize / 3; 7628cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_DIM_SCALE4, 7728cae868SHans Verkuil SOLO_DIM_H_MB_NUM(width / 16) | 7828cae868SHans Verkuil SOLO_DIM_V_MB_NUM_FRAME(height / 8) | 7928cae868SHans Verkuil SOLO_DIM_V_MB_NUM_FIELD(height / 16)); 8028cae868SHans Verkuil 8128cae868SHans Verkuil /* Set scale 5, 13 dimension */ 8228cae868SHans Verkuil width = solo_dev->video_hsize / 4; 8328cae868SHans Verkuil height = solo_dev->video_vsize / 2; 8428cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_DIM_SCALE5, 8528cae868SHans Verkuil SOLO_DIM_H_MB_NUM(width / 16) | 8628cae868SHans Verkuil SOLO_DIM_V_MB_NUM_FRAME(height / 8) | 8728cae868SHans Verkuil SOLO_DIM_V_MB_NUM_FIELD(height / 16)); 8828cae868SHans Verkuil 8928cae868SHans Verkuil /* Progressive */ 9028cae868SHans Verkuil width = VI_PROG_HSIZE; 9128cae868SHans Verkuil height = VI_PROG_VSIZE; 9228cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_DIM_PROG, 9328cae868SHans Verkuil SOLO_DIM_H_MB_NUM(width / 16) | 9428cae868SHans Verkuil SOLO_DIM_V_MB_NUM_FRAME(height / 16) | 9528cae868SHans Verkuil SOLO_DIM_V_MB_NUM_FIELD(height / 16)); 9628cae868SHans Verkuil 9728cae868SHans Verkuil /* Clear OSD */ 9828cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_OSD_CH, 0); 9928cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_OSD_BASE, SOLO_EOSD_EXT_ADDR >> 16); 10028cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_OSD_CLR, 10128cae868SHans Verkuil 0xF0 << 16 | 0x80 << 8 | 0x80); 10228cae868SHans Verkuil 10328cae868SHans Verkuil if (solo_dev->type == SOLO_DEV_6010) 10428cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, 10528cae868SHans Verkuil SOLO_VE_OSD_H_SHADOW | SOLO_VE_OSD_V_SHADOW); 10628cae868SHans Verkuil else 10728cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, SOLO_VE_OSD_V_DOUBLE 10828cae868SHans Verkuil | SOLO_VE_OSD_H_SHADOW | SOLO_VE_OSD_V_SHADOW); 10928cae868SHans Verkuil 11028cae868SHans Verkuil /* Clear OSG buffer */ 11128cae868SHans Verkuil buf = kzalloc(SOLO_EOSD_EXT_SIZE(solo_dev), GFP_KERNEL); 11228cae868SHans Verkuil if (!buf) 11328cae868SHans Verkuil return; 11428cae868SHans Verkuil 11528cae868SHans Verkuil for (i = 0; i < solo_dev->nr_chans; i++) { 11628cae868SHans Verkuil solo_p2m_dma(solo_dev, 1, buf, 11728cae868SHans Verkuil SOLO_EOSD_EXT_ADDR + 11828cae868SHans Verkuil (SOLO_EOSD_EXT_SIZE(solo_dev) * i), 11928cae868SHans Verkuil SOLO_EOSD_EXT_SIZE(solo_dev), 0, 0); 12028cae868SHans Verkuil } 12128cae868SHans Verkuil kfree(buf); 12228cae868SHans Verkuil } 12328cae868SHans Verkuil 12428cae868SHans Verkuil #define SOLO_OSD_WRITE_SIZE (16 * OSD_TEXT_MAX) 12528cae868SHans Verkuil 12628cae868SHans Verkuil /* Should be called with enable_lock held */ 12728cae868SHans Verkuil int solo_osd_print(struct solo_enc_dev *solo_enc) 12828cae868SHans Verkuil { 12928cae868SHans Verkuil struct solo_dev *solo_dev = solo_enc->solo_dev; 1308a4d9a9cSIsmael Luceno u8 *str = solo_enc->osd_text; 13128cae868SHans Verkuil u8 *buf = solo_enc->osd_buf; 13228cae868SHans Verkuil u32 reg; 13328cae868SHans Verkuil const struct font_desc *vga = find_font("VGA8x16"); 1348a4d9a9cSIsmael Luceno const u8 *vga_data; 13528cae868SHans Verkuil int i, j; 13628cae868SHans Verkuil 13728cae868SHans Verkuil if (WARN_ON_ONCE(!vga)) 13828cae868SHans Verkuil return -ENODEV; 13928cae868SHans Verkuil 14028cae868SHans Verkuil reg = solo_reg_read(solo_dev, SOLO_VE_OSD_CH); 14128cae868SHans Verkuil if (!*str) { 14228cae868SHans Verkuil /* Disable OSD on this channel */ 14328cae868SHans Verkuil reg &= ~(1 << solo_enc->ch); 14428cae868SHans Verkuil goto out; 14528cae868SHans Verkuil } 14628cae868SHans Verkuil 14728cae868SHans Verkuil memset(buf, 0, SOLO_OSD_WRITE_SIZE); 1488a4d9a9cSIsmael Luceno vga_data = (const u8 *)vga->data; 14928cae868SHans Verkuil 15028cae868SHans Verkuil for (i = 0; *str; i++, str++) { 15128cae868SHans Verkuil for (j = 0; j < 16; j++) { 15228cae868SHans Verkuil buf[(j << 1) | (i & 1) | ((i & ~1) << 4)] = 15328cae868SHans Verkuil bitrev8(vga_data[(*str << 4) | j]); 15428cae868SHans Verkuil } 15528cae868SHans Verkuil } 15628cae868SHans Verkuil 15728cae868SHans Verkuil solo_p2m_dma(solo_dev, 1, buf, 15828cae868SHans Verkuil SOLO_EOSD_EXT_ADDR_CHAN(solo_dev, solo_enc->ch), 15928cae868SHans Verkuil SOLO_OSD_WRITE_SIZE, 0, 0); 16028cae868SHans Verkuil 16128cae868SHans Verkuil /* Enable OSD on this channel */ 16228cae868SHans Verkuil reg |= (1 << solo_enc->ch); 16328cae868SHans Verkuil 16428cae868SHans Verkuil out: 16528cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg); 16628cae868SHans Verkuil return 0; 16728cae868SHans Verkuil } 16828cae868SHans Verkuil 169cba862dcSMauro Carvalho Chehab /* 17028cae868SHans Verkuil * Set channel Quality Profile (0-3). 17128cae868SHans Verkuil */ 17228cae868SHans Verkuil void solo_s_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch, 17328cae868SHans Verkuil unsigned int qp) 17428cae868SHans Verkuil { 17528cae868SHans Verkuil unsigned long flags; 17628cae868SHans Verkuil unsigned int idx, reg; 17728cae868SHans Verkuil 17828cae868SHans Verkuil if ((ch > 31) || (qp > 3)) 17928cae868SHans Verkuil return; 18028cae868SHans Verkuil 18128cae868SHans Verkuil if (solo_dev->type == SOLO_DEV_6010) 18228cae868SHans Verkuil return; 18328cae868SHans Verkuil 18428cae868SHans Verkuil if (ch < 16) { 18528cae868SHans Verkuil idx = 0; 18628cae868SHans Verkuil reg = SOLO_VE_JPEG_QP_CH_L; 18728cae868SHans Verkuil } else { 18828cae868SHans Verkuil ch -= 16; 18928cae868SHans Verkuil idx = 1; 19028cae868SHans Verkuil reg = SOLO_VE_JPEG_QP_CH_H; 19128cae868SHans Verkuil } 19228cae868SHans Verkuil ch *= 2; 19328cae868SHans Verkuil 19428cae868SHans Verkuil spin_lock_irqsave(&solo_dev->jpeg_qp_lock, flags); 19528cae868SHans Verkuil 19628cae868SHans Verkuil solo_dev->jpeg_qp[idx] &= ~(3 << ch); 19728cae868SHans Verkuil solo_dev->jpeg_qp[idx] |= (qp & 3) << ch; 19828cae868SHans Verkuil 19928cae868SHans Verkuil solo_reg_write(solo_dev, reg, solo_dev->jpeg_qp[idx]); 20028cae868SHans Verkuil 20128cae868SHans Verkuil spin_unlock_irqrestore(&solo_dev->jpeg_qp_lock, flags); 20228cae868SHans Verkuil } 20328cae868SHans Verkuil 20428cae868SHans Verkuil int solo_g_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch) 20528cae868SHans Verkuil { 20628cae868SHans Verkuil int idx; 20728cae868SHans Verkuil 20828cae868SHans Verkuil if (solo_dev->type == SOLO_DEV_6010) 20928cae868SHans Verkuil return 2; 21028cae868SHans Verkuil 21128cae868SHans Verkuil if (WARN_ON_ONCE(ch > 31)) 21228cae868SHans Verkuil return 2; 21328cae868SHans Verkuil 21428cae868SHans Verkuil if (ch < 16) { 21528cae868SHans Verkuil idx = 0; 21628cae868SHans Verkuil } else { 21728cae868SHans Verkuil ch -= 16; 21828cae868SHans Verkuil idx = 1; 21928cae868SHans Verkuil } 22028cae868SHans Verkuil ch *= 2; 22128cae868SHans Verkuil 22228cae868SHans Verkuil return (solo_dev->jpeg_qp[idx] >> ch) & 3; 22328cae868SHans Verkuil } 22428cae868SHans Verkuil 22528cae868SHans Verkuil #define SOLO_QP_INIT 0xaaaaaaaa 22628cae868SHans Verkuil 22728cae868SHans Verkuil static void solo_jpeg_config(struct solo_dev *solo_dev) 22828cae868SHans Verkuil { 22928cae868SHans Verkuil if (solo_dev->type == SOLO_DEV_6010) { 23028cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL, 23128cae868SHans Verkuil (2 << 24) | (2 << 16) | (2 << 8) | 2); 23228cae868SHans Verkuil } else { 23328cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL, 23428cae868SHans Verkuil (4 << 24) | (3 << 16) | (2 << 8) | 1); 23528cae868SHans Verkuil } 23628cae868SHans Verkuil 23728cae868SHans Verkuil spin_lock_init(&solo_dev->jpeg_qp_lock); 23828cae868SHans Verkuil 23928cae868SHans Verkuil /* Initialize Quality Profile for all channels */ 24028cae868SHans Verkuil solo_dev->jpeg_qp[0] = solo_dev->jpeg_qp[1] = SOLO_QP_INIT; 24128cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_L, SOLO_QP_INIT); 24228cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_H, SOLO_QP_INIT); 24328cae868SHans Verkuil 24428cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG, 24528cae868SHans Verkuil (SOLO_JPEG_EXT_SIZE(solo_dev) & 0xffff0000) | 24628cae868SHans Verkuil ((SOLO_JPEG_EXT_ADDR(solo_dev) >> 16) & 0x0000ffff)); 24728cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_JPEG_CTRL, 0xffffffff); 24828cae868SHans Verkuil if (solo_dev->type == SOLO_DEV_6110) { 24928cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG1, 25028cae868SHans Verkuil (0 << 16) | (30 << 8) | 60); 25128cae868SHans Verkuil } 25228cae868SHans Verkuil } 25328cae868SHans Verkuil 25428cae868SHans Verkuil static void solo_mp4e_config(struct solo_dev *solo_dev) 25528cae868SHans Verkuil { 25628cae868SHans Verkuil int i; 25728cae868SHans Verkuil u32 cfg; 25828cae868SHans Verkuil 25928cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_CFG0, 26028cae868SHans Verkuil SOLO_VE_INTR_CTRL(IRQ_LEVEL) | 26128cae868SHans Verkuil SOLO_VE_BLOCK_SIZE(SOLO_MP4E_EXT_SIZE(solo_dev) >> 16) | 26228cae868SHans Verkuil SOLO_VE_BLOCK_BASE(SOLO_MP4E_EXT_ADDR(solo_dev) >> 16)); 26328cae868SHans Verkuil 26428cae868SHans Verkuil 26528cae868SHans Verkuil cfg = SOLO_VE_BYTE_ALIGN(2) | SOLO_VE_INSERT_INDEX 26628cae868SHans Verkuil | SOLO_VE_MOTION_MODE(0); 26728cae868SHans Verkuil if (solo_dev->type != SOLO_DEV_6010) { 26828cae868SHans Verkuil cfg |= SOLO_VE_MPEG_SIZE_H( 26928cae868SHans Verkuil (SOLO_MP4E_EXT_SIZE(solo_dev) >> 24) & 0x0f); 27028cae868SHans Verkuil cfg |= SOLO_VE_JPEG_SIZE_H( 27128cae868SHans Verkuil (SOLO_JPEG_EXT_SIZE(solo_dev) >> 24) & 0x0f); 27228cae868SHans Verkuil } 27328cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_CFG1, cfg); 27428cae868SHans Verkuil 27528cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_WMRK_POLY, 0); 27628cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_VMRK_INIT_KEY, 0); 27728cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_WMRK_STRL, 0); 27828cae868SHans Verkuil if (solo_dev->type == SOLO_DEV_6110) 27928cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_WMRK_ENABLE, 0); 28028cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_ENCRYP_POLY, 0); 28128cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_ENCRYP_INIT, 0); 28228cae868SHans Verkuil 28328cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_ATTR, 28428cae868SHans Verkuil SOLO_VE_LITTLE_ENDIAN | 28528cae868SHans Verkuil SOLO_COMP_ATTR_FCODE(1) | 28628cae868SHans Verkuil SOLO_COMP_TIME_INC(0) | 28728cae868SHans Verkuil SOLO_COMP_TIME_WIDTH(15) | 28828cae868SHans Verkuil SOLO_DCT_INTERVAL(solo_dev->type == SOLO_DEV_6010 ? 9 : 10)); 28928cae868SHans Verkuil 29028cae868SHans Verkuil for (i = 0; i < solo_dev->nr_chans; i++) { 29128cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE(i), 29228cae868SHans Verkuil (SOLO_EREF_EXT_ADDR(solo_dev) + 29328cae868SHans Verkuil (i * SOLO_EREF_EXT_SIZE)) >> 16); 29428cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE_E(i), 29528cae868SHans Verkuil (SOLO_EREF_EXT_ADDR(solo_dev) + 29628cae868SHans Verkuil ((i + 16) * SOLO_EREF_EXT_SIZE)) >> 16); 29728cae868SHans Verkuil } 29828cae868SHans Verkuil 29928cae868SHans Verkuil if (solo_dev->type == SOLO_DEV_6110) { 30028cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_COMPT_MOT, 0x00040008); 30128cae868SHans Verkuil } else { 30228cae868SHans Verkuil for (i = 0; i < solo_dev->nr_chans; i++) 30328cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_VE_CH_MOT(i), 0x100); 30428cae868SHans Verkuil } 30528cae868SHans Verkuil } 30628cae868SHans Verkuil 30728cae868SHans Verkuil int solo_enc_init(struct solo_dev *solo_dev) 30828cae868SHans Verkuil { 30928cae868SHans Verkuil int i; 31028cae868SHans Verkuil 31128cae868SHans Verkuil solo_capture_config(solo_dev); 31228cae868SHans Verkuil solo_mp4e_config(solo_dev); 31328cae868SHans Verkuil solo_jpeg_config(solo_dev); 31428cae868SHans Verkuil 31528cae868SHans Verkuil for (i = 0; i < solo_dev->nr_chans; i++) { 31628cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0); 31728cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0); 31828cae868SHans Verkuil } 31928cae868SHans Verkuil 32028cae868SHans Verkuil return 0; 32128cae868SHans Verkuil } 32228cae868SHans Verkuil 32328cae868SHans Verkuil void solo_enc_exit(struct solo_dev *solo_dev) 32428cae868SHans Verkuil { 32528cae868SHans Verkuil int i; 32628cae868SHans Verkuil 32728cae868SHans Verkuil for (i = 0; i < solo_dev->nr_chans; i++) { 32828cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0); 32928cae868SHans Verkuil solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0); 33028cae868SHans Verkuil } 33128cae868SHans Verkuil } 332