Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com>
0004  *
0005  * Original author:
0006  * Ben Collins <bcollins@ubuntu.com>
0007  *
0008  * Additional work by:
0009  * John Brooks <john.brooks@bluecherry.net>
0010  */
0011 
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/videodev2.h>
0015 #include <media/v4l2-ioctl.h>
0016 
0017 #include "solo6x10.h"
0018 
0019 #define SOLO_VCLK_DELAY         3
0020 #define SOLO_PROGRESSIVE_VSIZE      1024
0021 
0022 #define SOLO_MOT_THRESH_W       64
0023 #define SOLO_MOT_THRESH_H       64
0024 #define SOLO_MOT_THRESH_SIZE        8192
0025 #define SOLO_MOT_THRESH_REAL        (SOLO_MOT_THRESH_W * SOLO_MOT_THRESH_H)
0026 #define SOLO_MOT_FLAG_SIZE      1024
0027 #define SOLO_MOT_FLAG_AREA      (SOLO_MOT_FLAG_SIZE * 16)
0028 
0029 static void solo_vin_config(struct solo_dev *solo_dev)
0030 {
0031     solo_dev->vin_hstart = 8;
0032     solo_dev->vin_vstart = 2;
0033 
0034     solo_reg_write(solo_dev, SOLO_SYS_VCLK,
0035                SOLO_VCLK_SELECT(2) |
0036                SOLO_VCLK_VIN1415_DELAY(SOLO_VCLK_DELAY) |
0037                SOLO_VCLK_VIN1213_DELAY(SOLO_VCLK_DELAY) |
0038                SOLO_VCLK_VIN1011_DELAY(SOLO_VCLK_DELAY) |
0039                SOLO_VCLK_VIN0809_DELAY(SOLO_VCLK_DELAY) |
0040                SOLO_VCLK_VIN0607_DELAY(SOLO_VCLK_DELAY) |
0041                SOLO_VCLK_VIN0405_DELAY(SOLO_VCLK_DELAY) |
0042                SOLO_VCLK_VIN0203_DELAY(SOLO_VCLK_DELAY) |
0043                SOLO_VCLK_VIN0001_DELAY(SOLO_VCLK_DELAY));
0044 
0045     solo_reg_write(solo_dev, SOLO_VI_ACT_I_P,
0046                SOLO_VI_H_START(solo_dev->vin_hstart) |
0047                SOLO_VI_V_START(solo_dev->vin_vstart) |
0048                SOLO_VI_V_STOP(solo_dev->vin_vstart +
0049                       solo_dev->video_vsize));
0050 
0051     solo_reg_write(solo_dev, SOLO_VI_ACT_I_S,
0052                SOLO_VI_H_START(solo_dev->vout_hstart) |
0053                SOLO_VI_V_START(solo_dev->vout_vstart) |
0054                SOLO_VI_V_STOP(solo_dev->vout_vstart +
0055                       solo_dev->video_vsize));
0056 
0057     solo_reg_write(solo_dev, SOLO_VI_ACT_P,
0058                SOLO_VI_H_START(0) |
0059                SOLO_VI_V_START(1) |
0060                SOLO_VI_V_STOP(SOLO_PROGRESSIVE_VSIZE));
0061 
0062     solo_reg_write(solo_dev, SOLO_VI_CH_FORMAT,
0063                SOLO_VI_FD_SEL_MASK(0) | SOLO_VI_PROG_MASK(0));
0064 
0065     /* On 6110, initialize mozaic darkness strength */
0066     if (solo_dev->type == SOLO_DEV_6010)
0067         solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 0);
0068     else
0069         solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 16 << 22);
0070 
0071     solo_reg_write(solo_dev, SOLO_VI_PAGE_SW, 2);
0072 
0073     if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
0074         solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG,
0075                    SOLO_VI_PB_USER_MODE);
0076         solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV,
0077                    SOLO_VI_PB_HSIZE(858) | SOLO_VI_PB_VSIZE(246));
0078         solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V,
0079                    SOLO_VI_PB_VSTART(4) |
0080                    SOLO_VI_PB_VSTOP(4 + 240));
0081     } else {
0082         solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG,
0083                    SOLO_VI_PB_USER_MODE | SOLO_VI_PB_PAL);
0084         solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV,
0085                    SOLO_VI_PB_HSIZE(864) | SOLO_VI_PB_VSIZE(294));
0086         solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V,
0087                    SOLO_VI_PB_VSTART(4) |
0088                    SOLO_VI_PB_VSTOP(4 + 288));
0089     }
0090     solo_reg_write(solo_dev, SOLO_VI_PB_ACT_H, SOLO_VI_PB_HSTART(16) |
0091                SOLO_VI_PB_HSTOP(16 + 720));
0092 }
0093 
0094 static void solo_vout_config_cursor(struct solo_dev *dev)
0095 {
0096     int i;
0097 
0098     /* Load (blank) cursor bitmap mask (2bpp) */
0099     for (i = 0; i < 20; i++)
0100         solo_reg_write(dev, SOLO_VO_CURSOR_MASK(i), 0);
0101 
0102     solo_reg_write(dev, SOLO_VO_CURSOR_POS, 0);
0103 
0104     solo_reg_write(dev, SOLO_VO_CURSOR_CLR,
0105                (0x80 << 24) | (0x80 << 16) | (0x10 << 8) | 0x80);
0106     solo_reg_write(dev, SOLO_VO_CURSOR_CLR2, (0xe0 << 8) | 0x80);
0107 }
0108 
0109 static void solo_vout_config(struct solo_dev *solo_dev)
0110 {
0111     solo_dev->vout_hstart = 6;
0112     solo_dev->vout_vstart = 8;
0113 
0114     solo_reg_write(solo_dev, SOLO_VO_FMT_ENC,
0115                solo_dev->video_type |
0116                SOLO_VO_USER_COLOR_SET_NAV |
0117                SOLO_VO_USER_COLOR_SET_NAH |
0118                SOLO_VO_NA_COLOR_Y(0) |
0119                SOLO_VO_NA_COLOR_CB(0) |
0120                SOLO_VO_NA_COLOR_CR(0));
0121 
0122     solo_reg_write(solo_dev, SOLO_VO_ACT_H,
0123                SOLO_VO_H_START(solo_dev->vout_hstart) |
0124                SOLO_VO_H_STOP(solo_dev->vout_hstart +
0125                       solo_dev->video_hsize));
0126 
0127     solo_reg_write(solo_dev, SOLO_VO_ACT_V,
0128                SOLO_VO_V_START(solo_dev->vout_vstart) |
0129                SOLO_VO_V_STOP(solo_dev->vout_vstart +
0130                       solo_dev->video_vsize));
0131 
0132     solo_reg_write(solo_dev, SOLO_VO_RANGE_HV,
0133                SOLO_VO_H_LEN(solo_dev->video_hsize) |
0134                SOLO_VO_V_LEN(solo_dev->video_vsize));
0135 
0136     /* Border & background colors */
0137     solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_COLOR,
0138                (0xa0 << 24) | (0x88 << 16) | (0xa0 << 8) | 0x88);
0139     solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_COLOR,
0140                (0x10 << 24) | (0x8f << 16) | (0x10 << 8) | 0x8f);
0141     solo_reg_write(solo_dev, SOLO_VO_BKG_COLOR,
0142                (16 << 24) | (128 << 16) | (16 << 8) | 128);
0143 
0144     solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
0145 
0146     solo_reg_write(solo_dev, SOLO_VI_WIN_SW, 0);
0147 
0148     solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0);
0149     solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0);
0150 
0151     solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, SOLO_VO_DISP_ON |
0152                SOLO_VO_DISP_ERASE_COUNT(8) |
0153                SOLO_VO_DISP_BASE(SOLO_DISP_EXT_ADDR));
0154 
0155 
0156     solo_vout_config_cursor(solo_dev);
0157 
0158     /* Enable channels we support */
0159     solo_reg_write(solo_dev, SOLO_VI_CH_ENA,
0160                (1 << solo_dev->nr_chans) - 1);
0161 }
0162 
0163 static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off,
0164                    u16 val, int reg_size)
0165 {
0166     __le16 *buf;
0167     const int n = 64, size = n * sizeof(*buf);
0168     int i, ret = 0;
0169 
0170     buf = kmalloc(size, GFP_KERNEL);
0171     if (!buf)
0172         return -ENOMEM;
0173 
0174     for (i = 0; i < n; i++)
0175         buf[i] = cpu_to_le16(val);
0176 
0177     for (i = 0; i < reg_size; i += size) {
0178         ret = solo_p2m_dma(solo_dev, 1, buf,
0179                    SOLO_MOTION_EXT_ADDR(solo_dev) + off + i,
0180                    size, 0, 0);
0181 
0182         if (ret)
0183             break;
0184     }
0185 
0186     kfree(buf);
0187     return ret;
0188 }
0189 
0190 int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val)
0191 {
0192     if (ch > solo_dev->nr_chans)
0193         return -EINVAL;
0194 
0195     return solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA +
0196                    (ch * SOLO_MOT_THRESH_SIZE * 2),
0197                    val, SOLO_MOT_THRESH_SIZE);
0198 }
0199 
0200 int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch,
0201         const u16 *thresholds)
0202 {
0203     const unsigned size = sizeof(u16) * 64;
0204     u32 off = SOLO_MOT_FLAG_AREA + ch * SOLO_MOT_THRESH_SIZE * 2;
0205     __le16 *buf;
0206     int x, y;
0207     int ret = 0;
0208 
0209     buf = kzalloc(size, GFP_KERNEL);
0210     if (buf == NULL)
0211         return -ENOMEM;
0212     for (y = 0; y < SOLO_MOTION_SZ; y++) {
0213         for (x = 0; x < SOLO_MOTION_SZ; x++)
0214             buf[x] = cpu_to_le16(thresholds[y * SOLO_MOTION_SZ + x]);
0215         ret |= solo_p2m_dma(solo_dev, 1, buf,
0216             SOLO_MOTION_EXT_ADDR(solo_dev) + off + y * size,
0217             size, 0, 0);
0218     }
0219     kfree(buf);
0220     return ret;
0221 }
0222 
0223 /* First 8k is motion flag (512 bytes * 16). Following that is an 8k+8k
0224  * threshold and working table for each channel. At least that's what the
0225  * spec says. However, this code (taken from rdk) has some mystery 8k
0226  * block right after the flag area, before the first thresh table. */
0227 static void solo_motion_config(struct solo_dev *solo_dev)
0228 {
0229     int i;
0230 
0231     for (i = 0; i < solo_dev->nr_chans; i++) {
0232         /* Clear motion flag area */
0233         solo_dma_vin_region(solo_dev, i * SOLO_MOT_FLAG_SIZE, 0x0000,
0234                     SOLO_MOT_FLAG_SIZE);
0235 
0236         /* Clear working cache table */
0237         solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA +
0238                     (i * SOLO_MOT_THRESH_SIZE * 2) +
0239                     SOLO_MOT_THRESH_SIZE, 0x0000,
0240                     SOLO_MOT_THRESH_SIZE);
0241 
0242         /* Set default threshold table */
0243         solo_set_motion_threshold(solo_dev, i, SOLO_DEF_MOT_THRESH);
0244     }
0245 
0246     /* Default motion settings */
0247     solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, SOLO_VI_MOTION_EN(0) |
0248                (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16));
0249     solo_reg_write(solo_dev, SOLO_VI_MOT_CTRL,
0250                SOLO_VI_MOTION_FRAME_COUNT(3) |
0251                SOLO_VI_MOTION_SAMPLE_LENGTH(solo_dev->video_hsize / 16)
0252                /* | SOLO_VI_MOTION_INTR_START_STOP */
0253                | SOLO_VI_MOTION_SAMPLE_COUNT(10));
0254 
0255     solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
0256     solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
0257 }
0258 
0259 int solo_disp_init(struct solo_dev *solo_dev)
0260 {
0261     int i;
0262 
0263     solo_dev->video_hsize = 704;
0264     if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
0265         solo_dev->video_vsize = 240;
0266         solo_dev->fps = 30;
0267     } else {
0268         solo_dev->video_vsize = 288;
0269         solo_dev->fps = 25;
0270     }
0271 
0272     solo_vin_config(solo_dev);
0273     solo_motion_config(solo_dev);
0274     solo_vout_config(solo_dev);
0275 
0276     for (i = 0; i < solo_dev->nr_chans; i++)
0277         solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 1);
0278 
0279     return 0;
0280 }
0281 
0282 void solo_disp_exit(struct solo_dev *solo_dev)
0283 {
0284     int i;
0285 
0286     solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, 0);
0287     solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0);
0288     solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0);
0289 
0290     for (i = 0; i < solo_dev->nr_chans; i++) {
0291         solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(i), 0);
0292         solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(i), 0);
0293         solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 0);
0294     }
0295 
0296     /* Set default border */
0297     for (i = 0; i < 5; i++)
0298         solo_reg_write(solo_dev, SOLO_VO_BORDER_X(i), 0);
0299 
0300     for (i = 0; i < 5; i++)
0301         solo_reg_write(solo_dev, SOLO_VO_BORDER_Y(i), 0);
0302 
0303     solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_MASK, 0);
0304     solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_MASK, 0);
0305 
0306     solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(0), 0);
0307     solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(0), 0);
0308     solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(0), 0);
0309 
0310     solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(1), 0);
0311     solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(1), 0);
0312     solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(1), 0);
0313 }