linux/drivers/gpu/drm/nouveau/dispnv04/tvmodesnv17.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2009 Francisco Jerez.
   3 * All Rights Reserved.
   4 *
   5 * Permission is hereby granted, free of charge, to any person obtaining
   6 * a copy of this software and associated documentation files (the
   7 * "Software"), to deal in the Software without restriction, including
   8 * without limitation the rights to use, copy, modify, merge, publish,
   9 * distribute, sublicense, and/or sell copies of the Software, and to
  10 * permit persons to whom the Software is furnished to do so, subject to
  11 * the following conditions:
  12 *
  13 * The above copyright notice and this permission notice (including the
  14 * next paragraph) shall be included in all copies or substantial
  15 * portions of the Software.
  16 *
  17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
  21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  24 *
  25 */
  26
  27#include <drm/drmP.h>
  28#include <drm/drm_crtc_helper.h>
  29#include "nouveau_drv.h"
  30#include "nouveau_encoder.h"
  31#include "nouveau_crtc.h"
  32#include "hw.h"
  33#include "tvnv17.h"
  34
  35const char * const nv17_tv_norm_names[NUM_TV_NORMS] = {
  36        [TV_NORM_PAL] = "PAL",
  37        [TV_NORM_PAL_M] = "PAL-M",
  38        [TV_NORM_PAL_N] = "PAL-N",
  39        [TV_NORM_PAL_NC] = "PAL-Nc",
  40        [TV_NORM_NTSC_M] = "NTSC-M",
  41        [TV_NORM_NTSC_J] = "NTSC-J",
  42        [TV_NORM_HD480I] = "hd480i",
  43        [TV_NORM_HD480P] = "hd480p",
  44        [TV_NORM_HD576I] = "hd576i",
  45        [TV_NORM_HD576P] = "hd576p",
  46        [TV_NORM_HD720P] = "hd720p",
  47        [TV_NORM_HD1080I] = "hd1080i"
  48};
  49
  50/* TV standard specific parameters */
  51
  52struct nv17_tv_norm_params nv17_tv_norms[NUM_TV_NORMS] = {
  53        [TV_NORM_PAL] = { TV_ENC_MODE, {
  54                        .tv_enc_mode = { 720, 576, 50000, {
  55                                        0x2a, 0x9, 0x8a, 0xcb, 0x0, 0x0, 0xb, 0x18,
  56                                        0x7e, 0x40, 0x8a, 0x35, 0x27, 0x0, 0x34, 0x3,
  57                                        0x3e, 0x3, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x9c,
  58                                        0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x3,
  59                                        0xd3, 0x4, 0xd4, 0x1, 0x2, 0x0, 0xa, 0x5,
  60                                        0x0, 0x1a, 0xff, 0x3, 0x18, 0xf, 0x78, 0x0,
  61                                        0x0, 0xb4, 0x0, 0x15, 0x49, 0x10, 0x0, 0x9b,
  62                                        0xbd, 0x15, 0x5, 0x15, 0x3e, 0x3, 0x0, 0x0
  63                                } } } },
  64
  65        [TV_NORM_PAL_M] = { TV_ENC_MODE, {
  66                        .tv_enc_mode = { 720, 480, 59940, {
  67                                        0x21, 0xe6, 0xef, 0xe3, 0x0, 0x0, 0xb, 0x18,
  68                                        0x7e, 0x44, 0x76, 0x32, 0x25, 0x0, 0x3c, 0x0,
  69                                        0x3c, 0x0, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x83,
  70                                        0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x1,
  71                                        0xc5, 0x4, 0xc5, 0x1, 0x2, 0x0, 0xa, 0x5,
  72                                        0x0, 0x18, 0xff, 0x3, 0x20, 0xf, 0x78, 0x0,
  73                                        0x0, 0xb4, 0x0, 0x15, 0x40, 0x10, 0x0, 0x9c,
  74                                        0xc8, 0x15, 0x5, 0x15, 0x3c, 0x0, 0x0, 0x0
  75                                } } } },
  76
  77        [TV_NORM_PAL_N] = { TV_ENC_MODE, {
  78                        .tv_enc_mode = { 720, 576, 50000, {
  79                                        0x2a, 0x9, 0x8a, 0xcb, 0x0, 0x0, 0xb, 0x18,
  80                                        0x7e, 0x40, 0x8a, 0x32, 0x25, 0x0, 0x3c, 0x0,
  81                                        0x3c, 0x0, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x9c,
  82                                        0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x1,
  83                                        0xc5, 0x4, 0xc5, 0x1, 0x2, 0x0, 0xa, 0x5,
  84                                        0x0, 0x1a, 0xff, 0x3, 0x18, 0xf, 0x78, 0x0,
  85                                        0x0, 0xb4, 0x0, 0x15, 0x49, 0x10, 0x0, 0x9b,
  86                                        0xbd, 0x15, 0x5, 0x15, 0x3c, 0x0, 0x0, 0x0
  87                                } } } },
  88
  89        [TV_NORM_PAL_NC] = { TV_ENC_MODE, {
  90                        .tv_enc_mode = { 720, 576, 50000, {
  91                                        0x21, 0xf6, 0x94, 0x46, 0x0, 0x0, 0xb, 0x18,
  92                                        0x7e, 0x44, 0x8a, 0x35, 0x27, 0x0, 0x34, 0x3,
  93                                        0x3e, 0x3, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x9c,
  94                                        0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x3,
  95                                        0xd3, 0x4, 0xd4, 0x1, 0x2, 0x0, 0xa, 0x5,
  96                                        0x0, 0x1a, 0xff, 0x3, 0x18, 0xf, 0x78, 0x0,
  97                                        0x0, 0xb4, 0x0, 0x15, 0x49, 0x10, 0x0, 0x9b,
  98                                        0xbd, 0x15, 0x5, 0x15, 0x3e, 0x3, 0x0, 0x0
  99                                } } } },
 100
 101        [TV_NORM_NTSC_M] = { TV_ENC_MODE, {
 102                        .tv_enc_mode = { 720, 480, 59940, {
 103                                        0x21, 0xf0, 0x7c, 0x1f, 0x0, 0x0, 0xb, 0x18,
 104                                        0x7e, 0x44, 0x76, 0x48, 0x0, 0x0, 0x3c, 0x0,
 105                                        0x3c, 0x0, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x83,
 106                                        0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x1,
 107                                        0xc5, 0x4, 0xc5, 0x1, 0x2, 0x0, 0xa, 0x5,
 108                                        0x0, 0x16, 0xff, 0x3, 0x20, 0xf, 0x78, 0x0,
 109                                        0x0, 0xb4, 0x0, 0x15, 0x4, 0x10, 0x0, 0x9c,
 110                                        0xc8, 0x15, 0x5, 0x15, 0x3c, 0x0, 0x0, 0x0
 111                                } } } },
 112
 113        [TV_NORM_NTSC_J] = { TV_ENC_MODE, {
 114                        .tv_enc_mode = { 720, 480, 59940, {
 115                                        0x21, 0xf0, 0x7c, 0x1f, 0x0, 0x0, 0xb, 0x18,
 116                                        0x7e, 0x44, 0x76, 0x48, 0x0, 0x0, 0x32, 0x0,
 117                                        0x3c, 0x0, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x83,
 118                                        0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x1,
 119                                        0xcf, 0x4, 0xcf, 0x1, 0x2, 0x0, 0xa, 0x5,
 120                                        0x0, 0x16, 0xff, 0x3, 0x20, 0xf, 0x78, 0x0,
 121                                        0x0, 0xb4, 0x0, 0x15, 0x4, 0x10, 0x0, 0xa4,
 122                                        0xc8, 0x15, 0x5, 0x15, 0x3c, 0x0, 0x0, 0x0
 123                                } } } },
 124
 125        [TV_NORM_HD480I] = { TV_ENC_MODE, {
 126                        .tv_enc_mode = { 720, 480, 59940, {
 127                                        0x21, 0xf0, 0x7c, 0x1f, 0x0, 0x0, 0xb, 0x18,
 128                                        0x7e, 0x44, 0x76, 0x48, 0x0, 0x0, 0x32, 0x0,
 129                                        0x3c, 0x0, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x83,
 130                                        0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x1,
 131                                        0xcf, 0x4, 0xcf, 0x1, 0x2, 0x0, 0xa, 0x5,
 132                                        0x0, 0x16, 0xff, 0x3, 0x20, 0xf, 0x78, 0x0,
 133                                        0x0, 0xb4, 0x0, 0x15, 0x4, 0x10, 0x0, 0xa4,
 134                                        0xc8, 0x15, 0x5, 0x15, 0x3c, 0x0, 0x0, 0x0
 135                                } } } },
 136
 137        [TV_NORM_HD576I] = { TV_ENC_MODE, {
 138                        .tv_enc_mode = { 720, 576, 50000, {
 139                                        0x2a, 0x9, 0x8a, 0xcb, 0x0, 0x0, 0xb, 0x18,
 140                                        0x7e, 0x40, 0x8a, 0x35, 0x27, 0x0, 0x34, 0x3,
 141                                        0x3e, 0x3, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x9c,
 142                                        0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x3,
 143                                        0xd3, 0x4, 0xd4, 0x1, 0x2, 0x0, 0xa, 0x5,
 144                                        0x0, 0x1a, 0xff, 0x3, 0x18, 0xf, 0x78, 0x0,
 145                                        0x0, 0xb4, 0x0, 0x15, 0x49, 0x10, 0x0, 0x9b,
 146                                        0xbd, 0x15, 0x5, 0x15, 0x3e, 0x3, 0x0, 0x0
 147                                } } } },
 148
 149
 150        [TV_NORM_HD480P] = { CTV_ENC_MODE, {
 151                        .ctv_enc_mode = {
 152                                .mode = { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000,
 153                                                   720, 735, 743, 858, 0, 480, 490, 494, 525, 0,
 154                                                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
 155                                .ctv_regs = { 0x3540000, 0x0, 0x0, 0x314,
 156                                              0x354003a, 0x40000, 0x6f0344, 0x18100000,
 157                                              0x10160004, 0x10060005, 0x1006000c, 0x10060020,
 158                                              0x10060021, 0x140e0022, 0x10060202, 0x1802020a,
 159                                              0x1810020b, 0x10000fff, 0x10000fff, 0x10000fff,
 160                                              0x10000fff, 0x10000fff, 0x10000fff, 0x70,
 161                                              0x3ff0000, 0x57, 0x2e001e, 0x258012c,
 162                                              0xa0aa04ec, 0x30, 0x80960019, 0x12c0300,
 163                                              0x2019, 0x600, 0x32060019, 0x0, 0x0, 0x400
 164                                } } } },
 165
 166        [TV_NORM_HD576P] = { CTV_ENC_MODE, {
 167                        .ctv_enc_mode = {
 168                                .mode = { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000,
 169                                                   720, 730, 738, 864, 0, 576, 581, 585, 625, 0,
 170                                                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
 171                                .ctv_regs = { 0x3540000, 0x0, 0x0, 0x314,
 172                                              0x354003a, 0x40000, 0x6f0344, 0x18100000,
 173                                              0x10060001, 0x10060009, 0x10060026, 0x10060027,
 174                                              0x140e0028, 0x10060268, 0x1810026d, 0x10000fff,
 175                                              0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff,
 176                                              0x10000fff, 0x10000fff, 0x10000fff, 0x69,
 177                                              0x3ff0000, 0x57, 0x2e001e, 0x258012c,
 178                                              0xa0aa04ec, 0x30, 0x80960019, 0x12c0300,
 179                                              0x2019, 0x600, 0x32060019, 0x0, 0x0, 0x400
 180                                } } } },
 181
 182        [TV_NORM_HD720P] = { CTV_ENC_MODE, {
 183                        .ctv_enc_mode = {
 184                                .mode = { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250,
 185                                                   1280, 1349, 1357, 1650, 0, 720, 725, 730, 750, 0,
 186                                                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
 187                                .ctv_regs = { 0x1260394, 0x0, 0x0, 0x622,
 188                                              0x66b0021, 0x6004a, 0x1210626, 0x8170000,
 189                                              0x70004, 0x70016, 0x70017, 0x40f0018,
 190                                              0x702e8, 0x81702ed, 0xfff, 0xfff,
 191                                              0xfff, 0xfff, 0xfff, 0xfff,
 192                                              0xfff, 0xfff, 0xfff, 0x0,
 193                                              0x2e40001, 0x58, 0x2e001e, 0x258012c,
 194                                              0xa0aa04ec, 0x30, 0x810c0039, 0x12c0300,
 195                                              0xc0002039, 0x600, 0x32060039, 0x0, 0x0, 0x0
 196                                } } } },
 197
 198        [TV_NORM_HD1080I] = { CTV_ENC_MODE, {
 199                        .ctv_enc_mode = {
 200                                .mode = { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250,
 201                                                   1920, 1961, 2049, 2200, 0, 1080, 1084, 1088, 1125, 0,
 202                                                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC
 203                                                   | DRM_MODE_FLAG_INTERLACE) },
 204                                .ctv_regs = { 0xac0420, 0x44c0478, 0x4a4, 0x4fc0868,
 205                                              0x8940028, 0x60054, 0xe80870, 0xbf70000,
 206                                              0xbc70004, 0x70005, 0x70012, 0x70013,
 207                                              0x40f0014, 0x70230, 0xbf70232, 0xbf70233,
 208                                              0x1c70237, 0x70238, 0x70244, 0x70245,
 209                                              0x40f0246, 0x70462, 0x1f70464, 0x0,
 210                                              0x2e40001, 0x58, 0x2e001e, 0x258012c,
 211                                              0xa0aa04ec, 0x30, 0x815f004c, 0x12c0300,
 212                                              0xc000204c, 0x600, 0x3206004c, 0x0, 0x0, 0x0
 213                                } } } }
 214};
 215
 216/*
 217 * The following is some guesswork on how the TV encoder flicker
 218 * filter/rescaler works:
 219 *
 220 * It seems to use some sort of resampling filter, it is controlled
 221 * through the registers at NV_PTV_HFILTER and NV_PTV_VFILTER, they
 222 * control the horizontal and vertical stage respectively, there is
 223 * also NV_PTV_HFILTER2 the blob fills identically to NV_PTV_HFILTER,
 224 * but they seem to do nothing. A rough guess might be that they could
 225 * be used to independently control the filtering of each interlaced
 226 * field, but I don't know how they are enabled. The whole filtering
 227 * process seems to be disabled with bits 26:27 of PTV_200, but we
 228 * aren't doing that.
 229 *
 230 * The layout of both register sets is the same:
 231 *
 232 * A: [BASE+0x18]...[BASE+0x0] [BASE+0x58]..[BASE+0x40]
 233 * B: [BASE+0x34]...[BASE+0x1c] [BASE+0x74]..[BASE+0x5c]
 234 *
 235 * Each coefficient is stored in bits [31],[15:9] in two's complement
 236 * format. They seem to be some kind of weights used in a low-pass
 237 * filter. Both A and B coefficients are applied to the 14 nearest
 238 * samples on each side (Listed from nearest to furthermost.  They
 239 * roughly cover 2 framebuffer pixels on each side).  They are
 240 * probably multiplied with some more hardwired weights before being
 241 * used: B-coefficients are applied the same on both sides,
 242 * A-coefficients are inverted before being applied to the opposite
 243 * side.
 244 *
 245 * After all the hassle, I got the following formula by empirical
 246 * means...
 247 */
 248
 249#define calc_overscan(o) interpolate(0x100, 0xe1, 0xc1, o)
 250
 251#define id1 (1LL << 8)
 252#define id2 (1LL << 16)
 253#define id3 (1LL << 24)
 254#define id4 (1LL << 32)
 255#define id5 (1LL << 48)
 256
 257static struct filter_params{
 258        int64_t k1;
 259        int64_t ki;
 260        int64_t ki2;
 261        int64_t ki3;
 262        int64_t kr;
 263        int64_t kir;
 264        int64_t ki2r;
 265        int64_t ki3r;
 266        int64_t kf;
 267        int64_t kif;
 268        int64_t ki2f;
 269        int64_t ki3f;
 270        int64_t krf;
 271        int64_t kirf;
 272        int64_t ki2rf;
 273        int64_t ki3rf;
 274} fparams[2][4] = {
 275        /* Horizontal filter parameters */
 276        {
 277                {64.311690 * id5, -39.516924 * id5, 6.586143 * id5, 0.000002 * id5,
 278                 0.051285 * id4, 26.168746 * id4, -4.361449 * id4, -0.000001 * id4,
 279                 9.308169 * id3, 78.180965 * id3, -13.030158 * id3, -0.000001 * id3,
 280                 -8.801540 * id1, -46.572890 * id1, 7.762145 * id1, -0.000000 * id1},
 281                {-44.565569 * id5, -68.081246 * id5, 39.812074 * id5, -4.009316 * id5,
 282                 29.832207 * id4, 50.047322 * id4, -25.380017 * id4, 2.546422 * id4,
 283                 104.605622 * id3, 141.908641 * id3, -74.322319 * id3, 7.484316 * id3,
 284                 -37.081621 * id1, -90.397510 * id1, 42.784229 * id1, -4.289952 * id1},
 285                {-56.793244 * id5, 31.153584 * id5, -5.192247 * id5, -0.000003 * id5,
 286                 33.541131 * id4, -34.149302 * id4, 5.691537 * id4, 0.000002 * id4,
 287                 87.196610 * id3, -88.995169 * id3, 14.832456 * id3, 0.000012 * id3,
 288                 17.288138 * id1, 71.864786 * id1, -11.977408 * id1, -0.000009 * id1},
 289                {51.787796 * id5, 21.211771 * id5, -18.993730 * id5, 1.853310 * id5,
 290                 -41.470726 * id4, -17.775823 * id4, 13.057821 * id4, -1.15823 * id4,
 291                 -154.235673 * id3, -44.878641 * id3, 40.656077 * id3, -3.695595 * id3,
 292                 112.201065 * id1, 39.992155 * id1, -25.155714 * id1, 2.113984 * id1},
 293        },
 294
 295        /* Vertical filter parameters */
 296        {
 297                {67.601979 * id5, 0.428319 * id5, -0.071318 * id5, -0.000012 * id5,
 298                 -3.402339 * id4, 0.000209 * id4, -0.000092 * id4, 0.000010 * id4,
 299                 -9.180996 * id3, 6.111270 * id3, -1.024457 * id3, 0.001043 * id3,
 300                 6.060315 * id1, -0.017425 * id1, 0.007830 * id1, -0.000869 * id1},
 301                {6.755647 * id5, 5.841348 * id5, 1.469734 * id5, -0.149656 * id5,
 302                 8.293120 * id4, -1.192888 * id4, -0.947652 * id4, 0.094507 * id4,
 303                 37.526655 * id3, 10.257875 * id3, -10.823275 * id3, 1.081497 * id3,
 304                 -2.361928 * id1, -2.059432 * id1, 1.840671 * id1, -0.168100 * id1},
 305                {-14.780391 * id5, -16.042148 * id5, 2.673692 * id5, -0.000000 * id5,
 306                 39.541978 * id4, 5.680053 * id4, -0.946676 * id4, 0.000000 * id4,
 307                 152.994486 * id3, 12.625439 * id3, -2.119579 * id3, 0.002708 * id3,
 308                 -38.125089 * id1, -0.855880 * id1, 0.155359 * id1, -0.002245 * id1},
 309                {-27.476193 * id5, -1.454976 * id5, 1.286557 * id5, 0.025346 * id5,
 310                 20.687300 * id4, 3.014003 * id4, -0.557786 * id4, -0.01311 * id4,
 311                 60.008737 * id3, -0.738273 * id3, 5.408217 * id3, -0.796798 * id3,
 312                 -17.296835 * id1, 4.438577 * id1, -2.809420 * id1, 0.385491 * id1},
 313        }
 314};
 315
 316static void tv_setup_filter(struct drm_encoder *encoder)
 317{
 318        struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
 319        struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
 320        struct drm_display_mode *mode = &encoder->crtc->mode;
 321        uint32_t (*filters[])[4][7] = {&tv_enc->state.hfilter,
 322                                       &tv_enc->state.vfilter};
 323        int i, j, k;
 324        int32_t overscan = calc_overscan(tv_enc->overscan);
 325        int64_t flicker = (tv_enc->flicker - 50) * (id3 / 100);
 326        uint64_t rs[] = {mode->hdisplay * id3,
 327                         mode->vdisplay * id3};
 328
 329        do_div(rs[0], overscan * tv_norm->tv_enc_mode.hdisplay);
 330        do_div(rs[1], overscan * tv_norm->tv_enc_mode.vdisplay);
 331
 332        for (k = 0; k < 2; k++) {
 333                rs[k] = max((int64_t)rs[k], id2);
 334
 335                for (j = 0; j < 4; j++) {
 336                        struct filter_params *p = &fparams[k][j];
 337
 338                        for (i = 0; i < 7; i++) {
 339                                int64_t c = (p->k1 + p->ki*i + p->ki2*i*i +
 340                                             p->ki3*i*i*i)
 341                                        + (p->kr + p->kir*i + p->ki2r*i*i +
 342                                           p->ki3r*i*i*i) * rs[k]
 343                                        + (p->kf + p->kif*i + p->ki2f*i*i +
 344                                           p->ki3f*i*i*i) * flicker
 345                                        + (p->krf + p->kirf*i + p->ki2rf*i*i +
 346                                           p->ki3rf*i*i*i) * flicker * rs[k];
 347
 348                                (*filters[k])[j][i] = (c + id5/2) >> 39
 349                                        & (0x1 << 31 | 0x7f << 9);
 350                        }
 351                }
 352        }
 353}
 354
 355/* Hardware state saving/restoring */
 356
 357static void tv_save_filter(struct drm_device *dev, uint32_t base,
 358                           uint32_t regs[4][7])
 359{
 360        int i, j;
 361        uint32_t offsets[] = { base, base + 0x1c, base + 0x40, base + 0x5c };
 362
 363        for (i = 0; i < 4; i++) {
 364                for (j = 0; j < 7; j++)
 365                        regs[i][j] = nv_read_ptv(dev, offsets[i]+4*j);
 366        }
 367}
 368
 369static void tv_load_filter(struct drm_device *dev, uint32_t base,
 370                           uint32_t regs[4][7])
 371{
 372        int i, j;
 373        uint32_t offsets[] = { base, base + 0x1c, base + 0x40, base + 0x5c };
 374
 375        for (i = 0; i < 4; i++) {
 376                for (j = 0; j < 7; j++)
 377                        nv_write_ptv(dev, offsets[i]+4*j, regs[i][j]);
 378        }
 379}
 380
 381void nv17_tv_state_save(struct drm_device *dev, struct nv17_tv_state *state)
 382{
 383        int i;
 384
 385        for (i = 0; i < 0x40; i++)
 386                state->tv_enc[i] = nv_read_tv_enc(dev, i);
 387
 388        tv_save_filter(dev, NV_PTV_HFILTER, state->hfilter);
 389        tv_save_filter(dev, NV_PTV_HFILTER2, state->hfilter2);
 390        tv_save_filter(dev, NV_PTV_VFILTER, state->vfilter);
 391
 392        nv_save_ptv(dev, state, 200);
 393        nv_save_ptv(dev, state, 204);
 394        nv_save_ptv(dev, state, 208);
 395        nv_save_ptv(dev, state, 20c);
 396        nv_save_ptv(dev, state, 304);
 397        nv_save_ptv(dev, state, 500);
 398        nv_save_ptv(dev, state, 504);
 399        nv_save_ptv(dev, state, 508);
 400        nv_save_ptv(dev, state, 600);
 401        nv_save_ptv(dev, state, 604);
 402        nv_save_ptv(dev, state, 608);
 403        nv_save_ptv(dev, state, 60c);
 404        nv_save_ptv(dev, state, 610);
 405        nv_save_ptv(dev, state, 614);
 406}
 407
 408void nv17_tv_state_load(struct drm_device *dev, struct nv17_tv_state *state)
 409{
 410        int i;
 411
 412        for (i = 0; i < 0x40; i++)
 413                nv_write_tv_enc(dev, i, state->tv_enc[i]);
 414
 415        tv_load_filter(dev, NV_PTV_HFILTER, state->hfilter);
 416        tv_load_filter(dev, NV_PTV_HFILTER2, state->hfilter2);
 417        tv_load_filter(dev, NV_PTV_VFILTER, state->vfilter);
 418
 419        nv_load_ptv(dev, state, 200);
 420        nv_load_ptv(dev, state, 204);
 421        nv_load_ptv(dev, state, 208);
 422        nv_load_ptv(dev, state, 20c);
 423        nv_load_ptv(dev, state, 304);
 424        nv_load_ptv(dev, state, 500);
 425        nv_load_ptv(dev, state, 504);
 426        nv_load_ptv(dev, state, 508);
 427        nv_load_ptv(dev, state, 600);
 428        nv_load_ptv(dev, state, 604);
 429        nv_load_ptv(dev, state, 608);
 430        nv_load_ptv(dev, state, 60c);
 431        nv_load_ptv(dev, state, 610);
 432        nv_load_ptv(dev, state, 614);
 433
 434        /* This is required for some settings to kick in. */
 435        nv_write_tv_enc(dev, 0x3e, 1);
 436        nv_write_tv_enc(dev, 0x3e, 0);
 437}
 438
 439/* Timings similar to the ones the blob sets */
 440
 441const struct drm_display_mode nv17_tv_modes[] = {
 442        { DRM_MODE("320x200", DRM_MODE_TYPE_DRIVER, 0,
 443                   320, 344, 392, 560, 0, 200, 200, 202, 220, 0,
 444                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC
 445                   | DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_CLKDIV2) },
 446        { DRM_MODE("320x240", DRM_MODE_TYPE_DRIVER, 0,
 447                   320, 344, 392, 560, 0, 240, 240, 246, 263, 0,
 448                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC
 449                   | DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_CLKDIV2) },
 450        { DRM_MODE("400x300", DRM_MODE_TYPE_DRIVER, 0,
 451                   400, 432, 496, 640, 0, 300, 300, 303, 314, 0,
 452                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC
 453                   | DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_CLKDIV2) },
 454        { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 0,
 455                   640, 672, 768, 880, 0, 480, 480, 492, 525, 0,
 456                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
 457        { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 0,
 458                   720, 752, 872, 960, 0, 480, 480, 493, 525, 0,
 459                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
 460        { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 0,
 461                   720, 776, 856, 960, 0, 576, 576, 588, 597, 0,
 462                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
 463        { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 0,
 464                   800, 840, 920, 1040, 0, 600, 600, 604, 618, 0,
 465                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
 466        { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 0,
 467                   1024, 1064, 1200, 1344, 0, 768, 768, 777, 806, 0,
 468                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
 469        {}
 470};
 471
 472void nv17_tv_update_properties(struct drm_encoder *encoder)
 473{
 474        struct drm_device *dev = encoder->dev;
 475        struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
 476        struct nv17_tv_state *regs = &tv_enc->state;
 477        struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
 478        int subconnector = tv_enc->select_subconnector ?
 479                                                tv_enc->select_subconnector :
 480                                                tv_enc->subconnector;
 481
 482        switch (subconnector) {
 483        case DRM_MODE_SUBCONNECTOR_Composite:
 484        {
 485                regs->ptv_204 = 0x2;
 486
 487                /* The composite connector may be found on either pin. */
 488                if (tv_enc->pin_mask & 0x4)
 489                        regs->ptv_204 |= 0x010000;
 490                else if (tv_enc->pin_mask & 0x2)
 491                        regs->ptv_204 |= 0x100000;
 492                else
 493                        regs->ptv_204 |= 0x110000;
 494
 495                regs->tv_enc[0x7] = 0x10;
 496                break;
 497        }
 498        case DRM_MODE_SUBCONNECTOR_SVIDEO:
 499                regs->ptv_204 = 0x11012;
 500                regs->tv_enc[0x7] = 0x18;
 501                break;
 502
 503        case DRM_MODE_SUBCONNECTOR_Component:
 504                regs->ptv_204 = 0x111333;
 505                regs->tv_enc[0x7] = 0x14;
 506                break;
 507
 508        case DRM_MODE_SUBCONNECTOR_SCART:
 509                regs->ptv_204 = 0x111012;
 510                regs->tv_enc[0x7] = 0x18;
 511                break;
 512        }
 513
 514        regs->tv_enc[0x20] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x20],
 515                                         255, tv_enc->saturation);
 516        regs->tv_enc[0x22] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x22],
 517                                         255, tv_enc->saturation);
 518        regs->tv_enc[0x25] = tv_enc->hue * 255 / 100;
 519
 520        nv_load_ptv(dev, regs, 204);
 521        nv_load_tv_enc(dev, regs, 7);
 522        nv_load_tv_enc(dev, regs, 20);
 523        nv_load_tv_enc(dev, regs, 22);
 524        nv_load_tv_enc(dev, regs, 25);
 525}
 526
 527void nv17_tv_update_rescaler(struct drm_encoder *encoder)
 528{
 529        struct drm_device *dev = encoder->dev;
 530        struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
 531        struct nv17_tv_state *regs = &tv_enc->state;
 532
 533        regs->ptv_208 = 0x40 | (calc_overscan(tv_enc->overscan) << 8);
 534
 535        tv_setup_filter(encoder);
 536
 537        nv_load_ptv(dev, regs, 208);
 538        tv_load_filter(dev, NV_PTV_HFILTER, regs->hfilter);
 539        tv_load_filter(dev, NV_PTV_HFILTER2, regs->hfilter2);
 540        tv_load_filter(dev, NV_PTV_VFILTER, regs->vfilter);
 541}
 542
 543void nv17_ctv_update_rescaler(struct drm_encoder *encoder)
 544{
 545        struct drm_device *dev = encoder->dev;
 546        struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
 547        int head = nouveau_crtc(encoder->crtc)->index;
 548        struct nv04_crtc_reg *regs = &nv04_display(dev)->mode_reg.crtc_reg[head];
 549        struct drm_display_mode *crtc_mode = &encoder->crtc->mode;
 550        struct drm_display_mode *output_mode =
 551                &get_tv_norm(encoder)->ctv_enc_mode.mode;
 552        int overscan, hmargin, vmargin, hratio, vratio;
 553
 554        /* The rescaler doesn't do the right thing for interlaced modes. */
 555        if (output_mode->flags & DRM_MODE_FLAG_INTERLACE)
 556                overscan = 100;
 557        else
 558                overscan = tv_enc->overscan;
 559
 560        hmargin = (output_mode->hdisplay - crtc_mode->hdisplay) / 2;
 561        vmargin = (output_mode->vdisplay - crtc_mode->vdisplay) / 2;
 562
 563        hmargin = interpolate(0, min(hmargin, output_mode->hdisplay/20),
 564                              hmargin, overscan);
 565        vmargin = interpolate(0, min(vmargin, output_mode->vdisplay/20),
 566                              vmargin, overscan);
 567
 568        hratio = crtc_mode->hdisplay * 0x800 /
 569                (output_mode->hdisplay - 2*hmargin);
 570        vratio = crtc_mode->vdisplay * 0x800 /
 571                (output_mode->vdisplay - 2*vmargin) & ~3;
 572
 573        regs->fp_horiz_regs[FP_VALID_START] = hmargin;
 574        regs->fp_horiz_regs[FP_VALID_END] = output_mode->hdisplay - hmargin - 1;
 575        regs->fp_vert_regs[FP_VALID_START] = vmargin;
 576        regs->fp_vert_regs[FP_VALID_END] = output_mode->vdisplay - vmargin - 1;
 577
 578        regs->fp_debug_1 = NV_PRAMDAC_FP_DEBUG_1_YSCALE_TESTMODE_ENABLE |
 579                XLATE(vratio, 0, NV_PRAMDAC_FP_DEBUG_1_YSCALE_VALUE) |
 580                NV_PRAMDAC_FP_DEBUG_1_XSCALE_TESTMODE_ENABLE |
 581                XLATE(hratio, 0, NV_PRAMDAC_FP_DEBUG_1_XSCALE_VALUE);
 582
 583        NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HVALID_START,
 584                      regs->fp_horiz_regs[FP_VALID_START]);
 585        NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HVALID_END,
 586                      regs->fp_horiz_regs[FP_VALID_END]);
 587        NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_VVALID_START,
 588                      regs->fp_vert_regs[FP_VALID_START]);
 589        NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_VVALID_END,
 590                      regs->fp_vert_regs[FP_VALID_END]);
 591        NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_DEBUG_1, regs->fp_debug_1);
 592}
 593