Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (C) 2009 Francisco Jerez.
0003  * All Rights Reserved.
0004  *
0005  * Permission is hereby granted, free of charge, to any person obtaining
0006  * a copy of this software and associated documentation files (the
0007  * "Software"), to deal in the Software without restriction, including
0008  * without limitation the rights to use, copy, modify, merge, publish,
0009  * distribute, sublicense, and/or sell copies of the Software, and to
0010  * permit persons to whom the Software is furnished to do so, subject to
0011  * the following conditions:
0012  *
0013  * The above copyright notice and this permission notice (including the
0014  * next paragraph) shall be included in all copies or substantial
0015  * portions of the Software.
0016  *
0017  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0018  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0019  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
0020  * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
0021  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
0022  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
0023  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0024  *
0025  */
0026 
0027 #include <drm/drm_crtc_helper.h>
0028 #include "nouveau_drv.h"
0029 #include "nouveau_encoder.h"
0030 #include "nouveau_crtc.h"
0031 #include "hw.h"
0032 #include "tvnv17.h"
0033 
0034 const char * const nv17_tv_norm_names[NUM_TV_NORMS] = {
0035     [TV_NORM_PAL] = "PAL",
0036     [TV_NORM_PAL_M] = "PAL-M",
0037     [TV_NORM_PAL_N] = "PAL-N",
0038     [TV_NORM_PAL_NC] = "PAL-Nc",
0039     [TV_NORM_NTSC_M] = "NTSC-M",
0040     [TV_NORM_NTSC_J] = "NTSC-J",
0041     [TV_NORM_HD480I] = "hd480i",
0042     [TV_NORM_HD480P] = "hd480p",
0043     [TV_NORM_HD576I] = "hd576i",
0044     [TV_NORM_HD576P] = "hd576p",
0045     [TV_NORM_HD720P] = "hd720p",
0046     [TV_NORM_HD1080I] = "hd1080i"
0047 };
0048 
0049 /* TV standard specific parameters */
0050 
0051 struct nv17_tv_norm_params nv17_tv_norms[NUM_TV_NORMS] = {
0052     [TV_NORM_PAL] = { TV_ENC_MODE, {
0053             .tv_enc_mode = { 720, 576, 50000, {
0054                     0x2a, 0x9, 0x8a, 0xcb, 0x0, 0x0, 0xb, 0x18,
0055                     0x7e, 0x40, 0x8a, 0x35, 0x27, 0x0, 0x34, 0x3,
0056                     0x3e, 0x3, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x9c,
0057                     0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x3,
0058                     0xd3, 0x4, 0xd4, 0x1, 0x2, 0x0, 0xa, 0x5,
0059                     0x0, 0x1a, 0xff, 0x3, 0x18, 0xf, 0x78, 0x0,
0060                     0x0, 0xb4, 0x0, 0x15, 0x49, 0x10, 0x0, 0x9b,
0061                     0xbd, 0x15, 0x5, 0x15, 0x3e, 0x3, 0x0, 0x0
0062                 } } } },
0063 
0064     [TV_NORM_PAL_M] = { TV_ENC_MODE, {
0065             .tv_enc_mode = { 720, 480, 59940, {
0066                     0x21, 0xe6, 0xef, 0xe3, 0x0, 0x0, 0xb, 0x18,
0067                     0x7e, 0x44, 0x76, 0x32, 0x25, 0x0, 0x3c, 0x0,
0068                     0x3c, 0x0, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x83,
0069                     0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x1,
0070                     0xc5, 0x4, 0xc5, 0x1, 0x2, 0x0, 0xa, 0x5,
0071                     0x0, 0x18, 0xff, 0x3, 0x20, 0xf, 0x78, 0x0,
0072                     0x0, 0xb4, 0x0, 0x15, 0x40, 0x10, 0x0, 0x9c,
0073                     0xc8, 0x15, 0x5, 0x15, 0x3c, 0x0, 0x0, 0x0
0074                 } } } },
0075 
0076     [TV_NORM_PAL_N] = { TV_ENC_MODE, {
0077             .tv_enc_mode = { 720, 576, 50000, {
0078                     0x2a, 0x9, 0x8a, 0xcb, 0x0, 0x0, 0xb, 0x18,
0079                     0x7e, 0x40, 0x8a, 0x32, 0x25, 0x0, 0x3c, 0x0,
0080                     0x3c, 0x0, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x9c,
0081                     0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x1,
0082                     0xc5, 0x4, 0xc5, 0x1, 0x2, 0x0, 0xa, 0x5,
0083                     0x0, 0x1a, 0xff, 0x3, 0x18, 0xf, 0x78, 0x0,
0084                     0x0, 0xb4, 0x0, 0x15, 0x49, 0x10, 0x0, 0x9b,
0085                     0xbd, 0x15, 0x5, 0x15, 0x3c, 0x0, 0x0, 0x0
0086                 } } } },
0087 
0088     [TV_NORM_PAL_NC] = { TV_ENC_MODE, {
0089             .tv_enc_mode = { 720, 576, 50000, {
0090                     0x21, 0xf6, 0x94, 0x46, 0x0, 0x0, 0xb, 0x18,
0091                     0x7e, 0x44, 0x8a, 0x35, 0x27, 0x0, 0x34, 0x3,
0092                     0x3e, 0x3, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x9c,
0093                     0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x3,
0094                     0xd3, 0x4, 0xd4, 0x1, 0x2, 0x0, 0xa, 0x5,
0095                     0x0, 0x1a, 0xff, 0x3, 0x18, 0xf, 0x78, 0x0,
0096                     0x0, 0xb4, 0x0, 0x15, 0x49, 0x10, 0x0, 0x9b,
0097                     0xbd, 0x15, 0x5, 0x15, 0x3e, 0x3, 0x0, 0x0
0098                 } } } },
0099 
0100     [TV_NORM_NTSC_M] = { TV_ENC_MODE, {
0101             .tv_enc_mode = { 720, 480, 59940, {
0102                     0x21, 0xf0, 0x7c, 0x1f, 0x0, 0x0, 0xb, 0x18,
0103                     0x7e, 0x44, 0x76, 0x48, 0x0, 0x0, 0x3c, 0x0,
0104                     0x3c, 0x0, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x83,
0105                     0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x1,
0106                     0xc5, 0x4, 0xc5, 0x1, 0x2, 0x0, 0xa, 0x5,
0107                     0x0, 0x16, 0xff, 0x3, 0x20, 0xf, 0x78, 0x0,
0108                     0x0, 0xb4, 0x0, 0x15, 0x4, 0x10, 0x0, 0x9c,
0109                     0xc8, 0x15, 0x5, 0x15, 0x3c, 0x0, 0x0, 0x0
0110                 } } } },
0111 
0112     [TV_NORM_NTSC_J] = { TV_ENC_MODE, {
0113             .tv_enc_mode = { 720, 480, 59940, {
0114                     0x21, 0xf0, 0x7c, 0x1f, 0x0, 0x0, 0xb, 0x18,
0115                     0x7e, 0x44, 0x76, 0x48, 0x0, 0x0, 0x32, 0x0,
0116                     0x3c, 0x0, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x83,
0117                     0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x1,
0118                     0xcf, 0x4, 0xcf, 0x1, 0x2, 0x0, 0xa, 0x5,
0119                     0x0, 0x16, 0xff, 0x3, 0x20, 0xf, 0x78, 0x0,
0120                     0x0, 0xb4, 0x0, 0x15, 0x4, 0x10, 0x0, 0xa4,
0121                     0xc8, 0x15, 0x5, 0x15, 0x3c, 0x0, 0x0, 0x0
0122                 } } } },
0123 
0124     [TV_NORM_HD480I] = { TV_ENC_MODE, {
0125             .tv_enc_mode = { 720, 480, 59940, {
0126                     0x21, 0xf0, 0x7c, 0x1f, 0x0, 0x0, 0xb, 0x18,
0127                     0x7e, 0x44, 0x76, 0x48, 0x0, 0x0, 0x32, 0x0,
0128                     0x3c, 0x0, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x83,
0129                     0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x1,
0130                     0xcf, 0x4, 0xcf, 0x1, 0x2, 0x0, 0xa, 0x5,
0131                     0x0, 0x16, 0xff, 0x3, 0x20, 0xf, 0x78, 0x0,
0132                     0x0, 0xb4, 0x0, 0x15, 0x4, 0x10, 0x0, 0xa4,
0133                     0xc8, 0x15, 0x5, 0x15, 0x3c, 0x0, 0x0, 0x0
0134                 } } } },
0135 
0136     [TV_NORM_HD576I] = { TV_ENC_MODE, {
0137             .tv_enc_mode = { 720, 576, 50000, {
0138                     0x2a, 0x9, 0x8a, 0xcb, 0x0, 0x0, 0xb, 0x18,
0139                     0x7e, 0x40, 0x8a, 0x35, 0x27, 0x0, 0x34, 0x3,
0140                     0x3e, 0x3, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x9c,
0141                     0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x3,
0142                     0xd3, 0x4, 0xd4, 0x1, 0x2, 0x0, 0xa, 0x5,
0143                     0x0, 0x1a, 0xff, 0x3, 0x18, 0xf, 0x78, 0x0,
0144                     0x0, 0xb4, 0x0, 0x15, 0x49, 0x10, 0x0, 0x9b,
0145                     0xbd, 0x15, 0x5, 0x15, 0x3e, 0x3, 0x0, 0x0
0146                 } } } },
0147 
0148 
0149     [TV_NORM_HD480P] = { CTV_ENC_MODE, {
0150             .ctv_enc_mode = {
0151                 .mode = { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000,
0152                            720, 735, 743, 858, 0, 480, 490, 494, 525, 0,
0153                            DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
0154                 .ctv_regs = { 0x3540000, 0x0, 0x0, 0x314,
0155                           0x354003a, 0x40000, 0x6f0344, 0x18100000,
0156                           0x10160004, 0x10060005, 0x1006000c, 0x10060020,
0157                           0x10060021, 0x140e0022, 0x10060202, 0x1802020a,
0158                           0x1810020b, 0x10000fff, 0x10000fff, 0x10000fff,
0159                           0x10000fff, 0x10000fff, 0x10000fff, 0x70,
0160                           0x3ff0000, 0x57, 0x2e001e, 0x258012c,
0161                           0xa0aa04ec, 0x30, 0x80960019, 0x12c0300,
0162                           0x2019, 0x600, 0x32060019, 0x0, 0x0, 0x400
0163                 } } } },
0164 
0165     [TV_NORM_HD576P] = { CTV_ENC_MODE, {
0166             .ctv_enc_mode = {
0167                 .mode = { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000,
0168                            720, 730, 738, 864, 0, 576, 581, 585, 625, 0,
0169                            DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
0170                 .ctv_regs = { 0x3540000, 0x0, 0x0, 0x314,
0171                           0x354003a, 0x40000, 0x6f0344, 0x18100000,
0172                           0x10060001, 0x10060009, 0x10060026, 0x10060027,
0173                           0x140e0028, 0x10060268, 0x1810026d, 0x10000fff,
0174                           0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff,
0175                           0x10000fff, 0x10000fff, 0x10000fff, 0x69,
0176                           0x3ff0000, 0x57, 0x2e001e, 0x258012c,
0177                           0xa0aa04ec, 0x30, 0x80960019, 0x12c0300,
0178                           0x2019, 0x600, 0x32060019, 0x0, 0x0, 0x400
0179                 } } } },
0180 
0181     [TV_NORM_HD720P] = { CTV_ENC_MODE, {
0182             .ctv_enc_mode = {
0183                 .mode = { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250,
0184                            1280, 1349, 1357, 1650, 0, 720, 725, 730, 750, 0,
0185                            DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
0186                 .ctv_regs = { 0x1260394, 0x0, 0x0, 0x622,
0187                           0x66b0021, 0x6004a, 0x1210626, 0x8170000,
0188                           0x70004, 0x70016, 0x70017, 0x40f0018,
0189                           0x702e8, 0x81702ed, 0xfff, 0xfff,
0190                           0xfff, 0xfff, 0xfff, 0xfff,
0191                           0xfff, 0xfff, 0xfff, 0x0,
0192                           0x2e40001, 0x58, 0x2e001e, 0x258012c,
0193                           0xa0aa04ec, 0x30, 0x810c0039, 0x12c0300,
0194                           0xc0002039, 0x600, 0x32060039, 0x0, 0x0, 0x0
0195                 } } } },
0196 
0197     [TV_NORM_HD1080I] = { CTV_ENC_MODE, {
0198             .ctv_enc_mode = {
0199                 .mode = { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250,
0200                            1920, 1961, 2049, 2200, 0, 1080, 1084, 1088, 1125, 0,
0201                            DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC
0202                            | DRM_MODE_FLAG_INTERLACE) },
0203                 .ctv_regs = { 0xac0420, 0x44c0478, 0x4a4, 0x4fc0868,
0204                           0x8940028, 0x60054, 0xe80870, 0xbf70000,
0205                           0xbc70004, 0x70005, 0x70012, 0x70013,
0206                           0x40f0014, 0x70230, 0xbf70232, 0xbf70233,
0207                           0x1c70237, 0x70238, 0x70244, 0x70245,
0208                           0x40f0246, 0x70462, 0x1f70464, 0x0,
0209                           0x2e40001, 0x58, 0x2e001e, 0x258012c,
0210                           0xa0aa04ec, 0x30, 0x815f004c, 0x12c0300,
0211                           0xc000204c, 0x600, 0x3206004c, 0x0, 0x0, 0x0
0212                 } } } }
0213 };
0214 
0215 /*
0216  * The following is some guesswork on how the TV encoder flicker
0217  * filter/rescaler works:
0218  *
0219  * It seems to use some sort of resampling filter, it is controlled
0220  * through the registers at NV_PTV_HFILTER and NV_PTV_VFILTER, they
0221  * control the horizontal and vertical stage respectively, there is
0222  * also NV_PTV_HFILTER2 the blob fills identically to NV_PTV_HFILTER,
0223  * but they seem to do nothing. A rough guess might be that they could
0224  * be used to independently control the filtering of each interlaced
0225  * field, but I don't know how they are enabled. The whole filtering
0226  * process seems to be disabled with bits 26:27 of PTV_200, but we
0227  * aren't doing that.
0228  *
0229  * The layout of both register sets is the same:
0230  *
0231  * A: [BASE+0x18]...[BASE+0x0] [BASE+0x58]..[BASE+0x40]
0232  * B: [BASE+0x34]...[BASE+0x1c] [BASE+0x74]..[BASE+0x5c]
0233  *
0234  * Each coefficient is stored in bits [31],[15:9] in two's complement
0235  * format. They seem to be some kind of weights used in a low-pass
0236  * filter. Both A and B coefficients are applied to the 14 nearest
0237  * samples on each side (Listed from nearest to furthermost.  They
0238  * roughly cover 2 framebuffer pixels on each side).  They are
0239  * probably multiplied with some more hardwired weights before being
0240  * used: B-coefficients are applied the same on both sides,
0241  * A-coefficients are inverted before being applied to the opposite
0242  * side.
0243  *
0244  * After all the hassle, I got the following formula by empirical
0245  * means...
0246  */
0247 
0248 #define calc_overscan(o) interpolate(0x100, 0xe1, 0xc1, o)
0249 
0250 #define id1 (1LL << 8)
0251 #define id2 (1LL << 16)
0252 #define id3 (1LL << 24)
0253 #define id4 (1LL << 32)
0254 #define id5 (1LL << 48)
0255 
0256 static struct filter_params{
0257     int64_t k1;
0258     int64_t ki;
0259     int64_t ki2;
0260     int64_t ki3;
0261     int64_t kr;
0262     int64_t kir;
0263     int64_t ki2r;
0264     int64_t ki3r;
0265     int64_t kf;
0266     int64_t kif;
0267     int64_t ki2f;
0268     int64_t ki3f;
0269     int64_t krf;
0270     int64_t kirf;
0271     int64_t ki2rf;
0272     int64_t ki3rf;
0273 } fparams[2][4] = {
0274     /* Horizontal filter parameters */
0275     {
0276         {64.311690 * id5, -39.516924 * id5, 6.586143 * id5, 0.000002 * id5,
0277          0.051285 * id4, 26.168746 * id4, -4.361449 * id4, -0.000001 * id4,
0278          9.308169 * id3, 78.180965 * id3, -13.030158 * id3, -0.000001 * id3,
0279          -8.801540 * id1, -46.572890 * id1, 7.762145 * id1, -0.000000 * id1},
0280         {-44.565569 * id5, -68.081246 * id5, 39.812074 * id5, -4.009316 * id5,
0281          29.832207 * id4, 50.047322 * id4, -25.380017 * id4, 2.546422 * id4,
0282          104.605622 * id3, 141.908641 * id3, -74.322319 * id3, 7.484316 * id3,
0283          -37.081621 * id1, -90.397510 * id1, 42.784229 * id1, -4.289952 * id1},
0284         {-56.793244 * id5, 31.153584 * id5, -5.192247 * id5, -0.000003 * id5,
0285          33.541131 * id4, -34.149302 * id4, 5.691537 * id4, 0.000002 * id4,
0286          87.196610 * id3, -88.995169 * id3, 14.832456 * id3, 0.000012 * id3,
0287          17.288138 * id1, 71.864786 * id1, -11.977408 * id1, -0.000009 * id1},
0288         {51.787796 * id5, 21.211771 * id5, -18.993730 * id5, 1.853310 * id5,
0289          -41.470726 * id4, -17.775823 * id4, 13.057821 * id4, -1.15823 * id4,
0290          -154.235673 * id3, -44.878641 * id3, 40.656077 * id3, -3.695595 * id3,
0291          112.201065 * id1, 39.992155 * id1, -25.155714 * id1, 2.113984 * id1},
0292     },
0293 
0294     /* Vertical filter parameters */
0295     {
0296         {67.601979 * id5, 0.428319 * id5, -0.071318 * id5, -0.000012 * id5,
0297          -3.402339 * id4, 0.000209 * id4, -0.000092 * id4, 0.000010 * id4,
0298          -9.180996 * id3, 6.111270 * id3, -1.024457 * id3, 0.001043 * id3,
0299          6.060315 * id1, -0.017425 * id1, 0.007830 * id1, -0.000869 * id1},
0300         {6.755647 * id5, 5.841348 * id5, 1.469734 * id5, -0.149656 * id5,
0301          8.293120 * id4, -1.192888 * id4, -0.947652 * id4, 0.094507 * id4,
0302          37.526655 * id3, 10.257875 * id3, -10.823275 * id3, 1.081497 * id3,
0303          -2.361928 * id1, -2.059432 * id1, 1.840671 * id1, -0.168100 * id1},
0304         {-14.780391 * id5, -16.042148 * id5, 2.673692 * id5, -0.000000 * id5,
0305          39.541978 * id4, 5.680053 * id4, -0.946676 * id4, 0.000000 * id4,
0306          152.994486 * id3, 12.625439 * id3, -2.119579 * id3, 0.002708 * id3,
0307          -38.125089 * id1, -0.855880 * id1, 0.155359 * id1, -0.002245 * id1},
0308         {-27.476193 * id5, -1.454976 * id5, 1.286557 * id5, 0.025346 * id5,
0309          20.687300 * id4, 3.014003 * id4, -0.557786 * id4, -0.01311 * id4,
0310          60.008737 * id3, -0.738273 * id3, 5.408217 * id3, -0.796798 * id3,
0311          -17.296835 * id1, 4.438577 * id1, -2.809420 * id1, 0.385491 * id1},
0312     }
0313 };
0314 
0315 static void tv_setup_filter(struct drm_encoder *encoder)
0316 {
0317     struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
0318     struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
0319     struct drm_display_mode *mode = &encoder->crtc->mode;
0320     uint32_t (*filters[])[4][7] = {&tv_enc->state.hfilter,
0321                        &tv_enc->state.vfilter};
0322     int i, j, k;
0323     int32_t overscan = calc_overscan(tv_enc->overscan);
0324     int64_t flicker = (tv_enc->flicker - 50) * (id3 / 100);
0325     uint64_t rs[] = {mode->hdisplay * id3,
0326              mode->vdisplay * id3};
0327 
0328     do_div(rs[0], overscan * tv_norm->tv_enc_mode.hdisplay);
0329     do_div(rs[1], overscan * tv_norm->tv_enc_mode.vdisplay);
0330 
0331     for (k = 0; k < 2; k++) {
0332         rs[k] = max((int64_t)rs[k], id2);
0333 
0334         for (j = 0; j < 4; j++) {
0335             struct filter_params *p = &fparams[k][j];
0336 
0337             for (i = 0; i < 7; i++) {
0338                 int64_t c = (p->k1 + p->ki*i + p->ki2*i*i +
0339                          p->ki3*i*i*i)
0340                     + (p->kr + p->kir*i + p->ki2r*i*i +
0341                        p->ki3r*i*i*i) * rs[k]
0342                     + (p->kf + p->kif*i + p->ki2f*i*i +
0343                        p->ki3f*i*i*i) * flicker
0344                     + (p->krf + p->kirf*i + p->ki2rf*i*i +
0345                        p->ki3rf*i*i*i) * flicker * rs[k];
0346 
0347                 (*filters[k])[j][i] = (c + id5/2) >> 39
0348                     & (0x1 << 31 | 0x7f << 9);
0349             }
0350         }
0351     }
0352 }
0353 
0354 /* Hardware state saving/restoring */
0355 
0356 static void tv_save_filter(struct drm_device *dev, uint32_t base,
0357                uint32_t regs[4][7])
0358 {
0359     int i, j;
0360     uint32_t offsets[] = { base, base + 0x1c, base + 0x40, base + 0x5c };
0361 
0362     for (i = 0; i < 4; i++) {
0363         for (j = 0; j < 7; j++)
0364             regs[i][j] = nv_read_ptv(dev, offsets[i]+4*j);
0365     }
0366 }
0367 
0368 static void tv_load_filter(struct drm_device *dev, uint32_t base,
0369                uint32_t regs[4][7])
0370 {
0371     int i, j;
0372     uint32_t offsets[] = { base, base + 0x1c, base + 0x40, base + 0x5c };
0373 
0374     for (i = 0; i < 4; i++) {
0375         for (j = 0; j < 7; j++)
0376             nv_write_ptv(dev, offsets[i]+4*j, regs[i][j]);
0377     }
0378 }
0379 
0380 void nv17_tv_state_save(struct drm_device *dev, struct nv17_tv_state *state)
0381 {
0382     int i;
0383 
0384     for (i = 0; i < 0x40; i++)
0385         state->tv_enc[i] = nv_read_tv_enc(dev, i);
0386 
0387     tv_save_filter(dev, NV_PTV_HFILTER, state->hfilter);
0388     tv_save_filter(dev, NV_PTV_HFILTER2, state->hfilter2);
0389     tv_save_filter(dev, NV_PTV_VFILTER, state->vfilter);
0390 
0391     nv_save_ptv(dev, state, 200);
0392     nv_save_ptv(dev, state, 204);
0393     nv_save_ptv(dev, state, 208);
0394     nv_save_ptv(dev, state, 20c);
0395     nv_save_ptv(dev, state, 304);
0396     nv_save_ptv(dev, state, 500);
0397     nv_save_ptv(dev, state, 504);
0398     nv_save_ptv(dev, state, 508);
0399     nv_save_ptv(dev, state, 600);
0400     nv_save_ptv(dev, state, 604);
0401     nv_save_ptv(dev, state, 608);
0402     nv_save_ptv(dev, state, 60c);
0403     nv_save_ptv(dev, state, 610);
0404     nv_save_ptv(dev, state, 614);
0405 }
0406 
0407 void nv17_tv_state_load(struct drm_device *dev, struct nv17_tv_state *state)
0408 {
0409     int i;
0410 
0411     for (i = 0; i < 0x40; i++)
0412         nv_write_tv_enc(dev, i, state->tv_enc[i]);
0413 
0414     tv_load_filter(dev, NV_PTV_HFILTER, state->hfilter);
0415     tv_load_filter(dev, NV_PTV_HFILTER2, state->hfilter2);
0416     tv_load_filter(dev, NV_PTV_VFILTER, state->vfilter);
0417 
0418     nv_load_ptv(dev, state, 200);
0419     nv_load_ptv(dev, state, 204);
0420     nv_load_ptv(dev, state, 208);
0421     nv_load_ptv(dev, state, 20c);
0422     nv_load_ptv(dev, state, 304);
0423     nv_load_ptv(dev, state, 500);
0424     nv_load_ptv(dev, state, 504);
0425     nv_load_ptv(dev, state, 508);
0426     nv_load_ptv(dev, state, 600);
0427     nv_load_ptv(dev, state, 604);
0428     nv_load_ptv(dev, state, 608);
0429     nv_load_ptv(dev, state, 60c);
0430     nv_load_ptv(dev, state, 610);
0431     nv_load_ptv(dev, state, 614);
0432 
0433     /* This is required for some settings to kick in. */
0434     nv_write_tv_enc(dev, 0x3e, 1);
0435     nv_write_tv_enc(dev, 0x3e, 0);
0436 }
0437 
0438 /* Timings similar to the ones the blob sets */
0439 
0440 const struct drm_display_mode nv17_tv_modes[] = {
0441     { DRM_MODE("320x200", DRM_MODE_TYPE_DRIVER, 0,
0442            320, 344, 392, 560, 0, 200, 200, 202, 220, 0,
0443            DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC
0444            | DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_CLKDIV2) },
0445     { DRM_MODE("320x240", DRM_MODE_TYPE_DRIVER, 0,
0446            320, 344, 392, 560, 0, 240, 240, 246, 263, 0,
0447            DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC
0448            | DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_CLKDIV2) },
0449     { DRM_MODE("400x300", DRM_MODE_TYPE_DRIVER, 0,
0450            400, 432, 496, 640, 0, 300, 300, 303, 314, 0,
0451            DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC
0452            | DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_CLKDIV2) },
0453     { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 0,
0454            640, 672, 768, 880, 0, 480, 480, 492, 525, 0,
0455            DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
0456     { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 0,
0457            720, 752, 872, 960, 0, 480, 480, 493, 525, 0,
0458            DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
0459     { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 0,
0460            720, 776, 856, 960, 0, 576, 576, 588, 597, 0,
0461            DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
0462     { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 0,
0463            800, 840, 920, 1040, 0, 600, 600, 604, 618, 0,
0464            DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
0465     { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 0,
0466            1024, 1064, 1200, 1344, 0, 768, 768, 777, 806, 0,
0467            DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
0468     {}
0469 };
0470 
0471 void nv17_tv_update_properties(struct drm_encoder *encoder)
0472 {
0473     struct drm_device *dev = encoder->dev;
0474     struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
0475     struct nv17_tv_state *regs = &tv_enc->state;
0476     struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
0477     int subconnector = tv_enc->select_subconnector ?
0478                         tv_enc->select_subconnector :
0479                         tv_enc->subconnector;
0480 
0481     switch (subconnector) {
0482     case DRM_MODE_SUBCONNECTOR_Composite:
0483     {
0484         regs->ptv_204 = 0x2;
0485 
0486         /* The composite connector may be found on either pin. */
0487         if (tv_enc->pin_mask & 0x4)
0488             regs->ptv_204 |= 0x010000;
0489         else if (tv_enc->pin_mask & 0x2)
0490             regs->ptv_204 |= 0x100000;
0491         else
0492             regs->ptv_204 |= 0x110000;
0493 
0494         regs->tv_enc[0x7] = 0x10;
0495         break;
0496     }
0497     case DRM_MODE_SUBCONNECTOR_SVIDEO:
0498         regs->ptv_204 = 0x11012;
0499         regs->tv_enc[0x7] = 0x18;
0500         break;
0501 
0502     case DRM_MODE_SUBCONNECTOR_Component:
0503         regs->ptv_204 = 0x111333;
0504         regs->tv_enc[0x7] = 0x14;
0505         break;
0506 
0507     case DRM_MODE_SUBCONNECTOR_SCART:
0508         regs->ptv_204 = 0x111012;
0509         regs->tv_enc[0x7] = 0x18;
0510         break;
0511     }
0512 
0513     regs->tv_enc[0x20] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x20],
0514                      255, tv_enc->saturation);
0515     regs->tv_enc[0x22] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x22],
0516                      255, tv_enc->saturation);
0517     regs->tv_enc[0x25] = tv_enc->hue * 255 / 100;
0518 
0519     nv_load_ptv(dev, regs, 204);
0520     nv_load_tv_enc(dev, regs, 7);
0521     nv_load_tv_enc(dev, regs, 20);
0522     nv_load_tv_enc(dev, regs, 22);
0523     nv_load_tv_enc(dev, regs, 25);
0524 }
0525 
0526 void nv17_tv_update_rescaler(struct drm_encoder *encoder)
0527 {
0528     struct drm_device *dev = encoder->dev;
0529     struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
0530     struct nv17_tv_state *regs = &tv_enc->state;
0531 
0532     regs->ptv_208 = 0x40 | (calc_overscan(tv_enc->overscan) << 8);
0533 
0534     tv_setup_filter(encoder);
0535 
0536     nv_load_ptv(dev, regs, 208);
0537     tv_load_filter(dev, NV_PTV_HFILTER, regs->hfilter);
0538     tv_load_filter(dev, NV_PTV_HFILTER2, regs->hfilter2);
0539     tv_load_filter(dev, NV_PTV_VFILTER, regs->vfilter);
0540 }
0541 
0542 void nv17_ctv_update_rescaler(struct drm_encoder *encoder)
0543 {
0544     struct drm_device *dev = encoder->dev;
0545     struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
0546     int head = nouveau_crtc(encoder->crtc)->index;
0547     struct nv04_crtc_reg *regs = &nv04_display(dev)->mode_reg.crtc_reg[head];
0548     struct drm_display_mode *crtc_mode = &encoder->crtc->mode;
0549     struct drm_display_mode *output_mode =
0550         &get_tv_norm(encoder)->ctv_enc_mode.mode;
0551     int overscan, hmargin, vmargin, hratio, vratio;
0552 
0553     /* The rescaler doesn't do the right thing for interlaced modes. */
0554     if (output_mode->flags & DRM_MODE_FLAG_INTERLACE)
0555         overscan = 100;
0556     else
0557         overscan = tv_enc->overscan;
0558 
0559     hmargin = (output_mode->hdisplay - crtc_mode->hdisplay) / 2;
0560     vmargin = (output_mode->vdisplay - crtc_mode->vdisplay) / 2;
0561 
0562     hmargin = interpolate(0, min(hmargin, output_mode->hdisplay/20),
0563                   hmargin, overscan);
0564     vmargin = interpolate(0, min(vmargin, output_mode->vdisplay/20),
0565                   vmargin, overscan);
0566 
0567     hratio = crtc_mode->hdisplay * 0x800 /
0568         (output_mode->hdisplay - 2*hmargin);
0569     vratio = crtc_mode->vdisplay * 0x800 /
0570         (output_mode->vdisplay - 2*vmargin) & ~3;
0571 
0572     regs->fp_horiz_regs[FP_VALID_START] = hmargin;
0573     regs->fp_horiz_regs[FP_VALID_END] = output_mode->hdisplay - hmargin - 1;
0574     regs->fp_vert_regs[FP_VALID_START] = vmargin;
0575     regs->fp_vert_regs[FP_VALID_END] = output_mode->vdisplay - vmargin - 1;
0576 
0577     regs->fp_debug_1 = NV_PRAMDAC_FP_DEBUG_1_YSCALE_TESTMODE_ENABLE |
0578         XLATE(vratio, 0, NV_PRAMDAC_FP_DEBUG_1_YSCALE_VALUE) |
0579         NV_PRAMDAC_FP_DEBUG_1_XSCALE_TESTMODE_ENABLE |
0580         XLATE(hratio, 0, NV_PRAMDAC_FP_DEBUG_1_XSCALE_VALUE);
0581 
0582     NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HVALID_START,
0583               regs->fp_horiz_regs[FP_VALID_START]);
0584     NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HVALID_END,
0585               regs->fp_horiz_regs[FP_VALID_END]);
0586     NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_VVALID_START,
0587               regs->fp_vert_regs[FP_VALID_START]);
0588     NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_VVALID_END,
0589               regs->fp_vert_regs[FP_VALID_END]);
0590     NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_DEBUG_1, regs->fp_debug_1);
0591 }