root/drivers/media/pci/solo6x10/solo6x10-disp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. solo_vin_config
  2. solo_vout_config_cursor
  3. solo_vout_config
  4. solo_dma_vin_region
  5. solo_set_motion_threshold
  6. solo_set_motion_block
  7. solo_motion_config
  8. solo_disp_init
  9. solo_disp_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright (C) 2010-2013 Bluecherry, LLC <http://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/module.h>
  14 #include <linux/videodev2.h>
  15 #include <media/v4l2-ioctl.h>
  16 
  17 #include "solo6x10.h"
  18 
  19 #define SOLO_VCLK_DELAY                 3
  20 #define SOLO_PROGRESSIVE_VSIZE          1024
  21 
  22 #define SOLO_MOT_THRESH_W               64
  23 #define SOLO_MOT_THRESH_H               64
  24 #define SOLO_MOT_THRESH_SIZE            8192
  25 #define SOLO_MOT_THRESH_REAL            (SOLO_MOT_THRESH_W * SOLO_MOT_THRESH_H)
  26 #define SOLO_MOT_FLAG_SIZE              1024
  27 #define SOLO_MOT_FLAG_AREA              (SOLO_MOT_FLAG_SIZE * 16)
  28 
  29 static void solo_vin_config(struct solo_dev *solo_dev)
  30 {
  31         solo_dev->vin_hstart = 8;
  32         solo_dev->vin_vstart = 2;
  33 
  34         solo_reg_write(solo_dev, SOLO_SYS_VCLK,
  35                        SOLO_VCLK_SELECT(2) |
  36                        SOLO_VCLK_VIN1415_DELAY(SOLO_VCLK_DELAY) |
  37                        SOLO_VCLK_VIN1213_DELAY(SOLO_VCLK_DELAY) |
  38                        SOLO_VCLK_VIN1011_DELAY(SOLO_VCLK_DELAY) |
  39                        SOLO_VCLK_VIN0809_DELAY(SOLO_VCLK_DELAY) |
  40                        SOLO_VCLK_VIN0607_DELAY(SOLO_VCLK_DELAY) |
  41                        SOLO_VCLK_VIN0405_DELAY(SOLO_VCLK_DELAY) |
  42                        SOLO_VCLK_VIN0203_DELAY(SOLO_VCLK_DELAY) |
  43                        SOLO_VCLK_VIN0001_DELAY(SOLO_VCLK_DELAY));
  44 
  45         solo_reg_write(solo_dev, SOLO_VI_ACT_I_P,
  46                        SOLO_VI_H_START(solo_dev->vin_hstart) |
  47                        SOLO_VI_V_START(solo_dev->vin_vstart) |
  48                        SOLO_VI_V_STOP(solo_dev->vin_vstart +
  49                                       solo_dev->video_vsize));
  50 
  51         solo_reg_write(solo_dev, SOLO_VI_ACT_I_S,
  52                        SOLO_VI_H_START(solo_dev->vout_hstart) |
  53                        SOLO_VI_V_START(solo_dev->vout_vstart) |
  54                        SOLO_VI_V_STOP(solo_dev->vout_vstart +
  55                                       solo_dev->video_vsize));
  56 
  57         solo_reg_write(solo_dev, SOLO_VI_ACT_P,
  58                        SOLO_VI_H_START(0) |
  59                        SOLO_VI_V_START(1) |
  60                        SOLO_VI_V_STOP(SOLO_PROGRESSIVE_VSIZE));
  61 
  62         solo_reg_write(solo_dev, SOLO_VI_CH_FORMAT,
  63                        SOLO_VI_FD_SEL_MASK(0) | SOLO_VI_PROG_MASK(0));
  64 
  65         /* On 6110, initialize mozaic darkness strength */
  66         if (solo_dev->type == SOLO_DEV_6010)
  67                 solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 0);
  68         else
  69                 solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 16 << 22);
  70 
  71         solo_reg_write(solo_dev, SOLO_VI_PAGE_SW, 2);
  72 
  73         if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
  74                 solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG,
  75                                SOLO_VI_PB_USER_MODE);
  76                 solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV,
  77                                SOLO_VI_PB_HSIZE(858) | SOLO_VI_PB_VSIZE(246));
  78                 solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V,
  79                                SOLO_VI_PB_VSTART(4) |
  80                                SOLO_VI_PB_VSTOP(4 + 240));
  81         } else {
  82                 solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG,
  83                                SOLO_VI_PB_USER_MODE | SOLO_VI_PB_PAL);
  84                 solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV,
  85                                SOLO_VI_PB_HSIZE(864) | SOLO_VI_PB_VSIZE(294));
  86                 solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V,
  87                                SOLO_VI_PB_VSTART(4) |
  88                                SOLO_VI_PB_VSTOP(4 + 288));
  89         }
  90         solo_reg_write(solo_dev, SOLO_VI_PB_ACT_H, SOLO_VI_PB_HSTART(16) |
  91                        SOLO_VI_PB_HSTOP(16 + 720));
  92 }
  93 
  94 static void solo_vout_config_cursor(struct solo_dev *dev)
  95 {
  96         int i;
  97 
  98         /* Load (blank) cursor bitmap mask (2bpp) */
  99         for (i = 0; i < 20; i++)
 100                 solo_reg_write(dev, SOLO_VO_CURSOR_MASK(i), 0);
 101 
 102         solo_reg_write(dev, SOLO_VO_CURSOR_POS, 0);
 103 
 104         solo_reg_write(dev, SOLO_VO_CURSOR_CLR,
 105                        (0x80 << 24) | (0x80 << 16) | (0x10 << 8) | 0x80);
 106         solo_reg_write(dev, SOLO_VO_CURSOR_CLR2, (0xe0 << 8) | 0x80);
 107 }
 108 
 109 static void solo_vout_config(struct solo_dev *solo_dev)
 110 {
 111         solo_dev->vout_hstart = 6;
 112         solo_dev->vout_vstart = 8;
 113 
 114         solo_reg_write(solo_dev, SOLO_VO_FMT_ENC,
 115                        solo_dev->video_type |
 116                        SOLO_VO_USER_COLOR_SET_NAV |
 117                        SOLO_VO_USER_COLOR_SET_NAH |
 118                        SOLO_VO_NA_COLOR_Y(0) |
 119                        SOLO_VO_NA_COLOR_CB(0) |
 120                        SOLO_VO_NA_COLOR_CR(0));
 121 
 122         solo_reg_write(solo_dev, SOLO_VO_ACT_H,
 123                        SOLO_VO_H_START(solo_dev->vout_hstart) |
 124                        SOLO_VO_H_STOP(solo_dev->vout_hstart +
 125                                       solo_dev->video_hsize));
 126 
 127         solo_reg_write(solo_dev, SOLO_VO_ACT_V,
 128                        SOLO_VO_V_START(solo_dev->vout_vstart) |
 129                        SOLO_VO_V_STOP(solo_dev->vout_vstart +
 130                                       solo_dev->video_vsize));
 131 
 132         solo_reg_write(solo_dev, SOLO_VO_RANGE_HV,
 133                        SOLO_VO_H_LEN(solo_dev->video_hsize) |
 134                        SOLO_VO_V_LEN(solo_dev->video_vsize));
 135 
 136         /* Border & background colors */
 137         solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_COLOR,
 138                        (0xa0 << 24) | (0x88 << 16) | (0xa0 << 8) | 0x88);
 139         solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_COLOR,
 140                        (0x10 << 24) | (0x8f << 16) | (0x10 << 8) | 0x8f);
 141         solo_reg_write(solo_dev, SOLO_VO_BKG_COLOR,
 142                        (16 << 24) | (128 << 16) | (16 << 8) | 128);
 143 
 144         solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
 145 
 146         solo_reg_write(solo_dev, SOLO_VI_WIN_SW, 0);
 147 
 148         solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0);
 149         solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0);
 150 
 151         solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, SOLO_VO_DISP_ON |
 152                        SOLO_VO_DISP_ERASE_COUNT(8) |
 153                        SOLO_VO_DISP_BASE(SOLO_DISP_EXT_ADDR));
 154 
 155 
 156         solo_vout_config_cursor(solo_dev);
 157 
 158         /* Enable channels we support */
 159         solo_reg_write(solo_dev, SOLO_VI_CH_ENA,
 160                        (1 << solo_dev->nr_chans) - 1);
 161 }
 162 
 163 static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off,
 164                                u16 val, int reg_size)
 165 {
 166         __le16 *buf;
 167         const int n = 64, size = n * sizeof(*buf);
 168         int i, ret = 0;
 169 
 170         buf = kmalloc(size, GFP_KERNEL);
 171         if (!buf)
 172                 return -ENOMEM;
 173 
 174         for (i = 0; i < n; i++)
 175                 buf[i] = cpu_to_le16(val);
 176 
 177         for (i = 0; i < reg_size; i += size) {
 178                 ret = solo_p2m_dma(solo_dev, 1, buf,
 179                                    SOLO_MOTION_EXT_ADDR(solo_dev) + off + i,
 180                                    size, 0, 0);
 181 
 182                 if (ret)
 183                         break;
 184         }
 185 
 186         kfree(buf);
 187         return ret;
 188 }
 189 
 190 int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val)
 191 {
 192         if (ch > solo_dev->nr_chans)
 193                 return -EINVAL;
 194 
 195         return solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA +
 196                                    (ch * SOLO_MOT_THRESH_SIZE * 2),
 197                                    val, SOLO_MOT_THRESH_SIZE);
 198 }
 199 
 200 int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch,
 201                 const u16 *thresholds)
 202 {
 203         const unsigned size = sizeof(u16) * 64;
 204         u32 off = SOLO_MOT_FLAG_AREA + ch * SOLO_MOT_THRESH_SIZE * 2;
 205         __le16 *buf;
 206         int x, y;
 207         int ret = 0;
 208 
 209         buf = kzalloc(size, GFP_KERNEL);
 210         if (buf == NULL)
 211                 return -ENOMEM;
 212         for (y = 0; y < SOLO_MOTION_SZ; y++) {
 213                 for (x = 0; x < SOLO_MOTION_SZ; x++)
 214                         buf[x] = cpu_to_le16(thresholds[y * SOLO_MOTION_SZ + x]);
 215                 ret |= solo_p2m_dma(solo_dev, 1, buf,
 216                         SOLO_MOTION_EXT_ADDR(solo_dev) + off + y * size,
 217                         size, 0, 0);
 218         }
 219         kfree(buf);
 220         return ret;
 221 }
 222 
 223 /* First 8k is motion flag (512 bytes * 16). Following that is an 8k+8k
 224  * threshold and working table for each channel. At least that's what the
 225  * spec says. However, this code (taken from rdk) has some mystery 8k
 226  * block right after the flag area, before the first thresh table. */
 227 static void solo_motion_config(struct solo_dev *solo_dev)
 228 {
 229         int i;
 230 
 231         for (i = 0; i < solo_dev->nr_chans; i++) {
 232                 /* Clear motion flag area */
 233                 solo_dma_vin_region(solo_dev, i * SOLO_MOT_FLAG_SIZE, 0x0000,
 234                                     SOLO_MOT_FLAG_SIZE);
 235 
 236                 /* Clear working cache table */
 237                 solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA +
 238                                     (i * SOLO_MOT_THRESH_SIZE * 2) +
 239                                     SOLO_MOT_THRESH_SIZE, 0x0000,
 240                                     SOLO_MOT_THRESH_SIZE);
 241 
 242                 /* Set default threshold table */
 243                 solo_set_motion_threshold(solo_dev, i, SOLO_DEF_MOT_THRESH);
 244         }
 245 
 246         /* Default motion settings */
 247         solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, SOLO_VI_MOTION_EN(0) |
 248                        (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16));
 249         solo_reg_write(solo_dev, SOLO_VI_MOT_CTRL,
 250                        SOLO_VI_MOTION_FRAME_COUNT(3) |
 251                        SOLO_VI_MOTION_SAMPLE_LENGTH(solo_dev->video_hsize / 16)
 252                        /* | SOLO_VI_MOTION_INTR_START_STOP */
 253                        | SOLO_VI_MOTION_SAMPLE_COUNT(10));
 254 
 255         solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
 256         solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
 257 }
 258 
 259 int solo_disp_init(struct solo_dev *solo_dev)
 260 {
 261         int i;
 262 
 263         solo_dev->video_hsize = 704;
 264         if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
 265                 solo_dev->video_vsize = 240;
 266                 solo_dev->fps = 30;
 267         } else {
 268                 solo_dev->video_vsize = 288;
 269                 solo_dev->fps = 25;
 270         }
 271 
 272         solo_vin_config(solo_dev);
 273         solo_motion_config(solo_dev);
 274         solo_vout_config(solo_dev);
 275 
 276         for (i = 0; i < solo_dev->nr_chans; i++)
 277                 solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 1);
 278 
 279         return 0;
 280 }
 281 
 282 void solo_disp_exit(struct solo_dev *solo_dev)
 283 {
 284         int i;
 285 
 286         solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, 0);
 287         solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0);
 288         solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0);
 289 
 290         for (i = 0; i < solo_dev->nr_chans; i++) {
 291                 solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(i), 0);
 292                 solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(i), 0);
 293                 solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 0);
 294         }
 295 
 296         /* Set default border */
 297         for (i = 0; i < 5; i++)
 298                 solo_reg_write(solo_dev, SOLO_VO_BORDER_X(i), 0);
 299 
 300         for (i = 0; i < 5; i++)
 301                 solo_reg_write(solo_dev, SOLO_VO_BORDER_Y(i), 0);
 302 
 303         solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_MASK, 0);
 304         solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_MASK, 0);
 305 
 306         solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(0), 0);
 307         solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(0), 0);
 308         solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(0), 0);
 309 
 310         solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(1), 0);
 311         solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(1), 0);
 312         solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(1), 0);
 313 }

/* [<][>][^][v][top][bottom][index][help] */