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 "drmP.h" 28#include "drm_crtc_helper.h" 29#include "nouveau_drv.h" 30#include "nouveau_encoder.h" 31#include "nouveau_crtc.h" 32#include "nouveau_hw.h" 33#include "nv17_tv.h" 34 35char *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 + p->ki3*i*i*i) 340 + (p->kr + p->kir*i + p->ki2r*i*i + p->ki3r*i*i*i)*rs[k] 341 + (p->kf + p->kif*i + p->ki2f*i*i + p->ki3f*i*i*i)*flicker 342 + (p->krf + p->kirf*i + p->ki2rf*i*i + p->ki3rf*i*i*i)*flicker*rs[k]; 343 344 (*filters[k])[j][i] = (c + id5/2) >> 39 & (0x1 << 31 | 0x7f << 9); 345 } 346 } 347 } 348} 349 350/* Hardware state saving/restoring */ 351 352static void tv_save_filter(struct drm_device *dev, uint32_t base, uint32_t regs[4][7]) 353{ 354 int i, j; 355 uint32_t offsets[] = { base, base + 0x1c, base + 0x40, base + 0x5c }; 356 357 for (i = 0; i < 4; i++) { 358 for (j = 0; j < 7; j++) 359 regs[i][j] = nv_read_ptv(dev, offsets[i]+4*j); 360 } 361} 362 363static void tv_load_filter(struct drm_device *dev, uint32_t base, uint32_t regs[4][7]) 364{ 365 int i, j; 366 uint32_t offsets[] = { base, base + 0x1c, base + 0x40, base + 0x5c }; 367 368 for (i = 0; i < 4; i++) { 369 for (j = 0; j < 7; j++) 370 nv_write_ptv(dev, offsets[i]+4*j, regs[i][j]); 371 } 372} 373 374void nv17_tv_state_save(struct drm_device *dev, struct nv17_tv_state *state) 375{ 376 int i; 377 378 for (i = 0; i < 0x40; i++) 379 state->tv_enc[i] = nv_read_tv_enc(dev, i); 380 381 tv_save_filter(dev, NV_PTV_HFILTER, state->hfilter); 382 tv_save_filter(dev, NV_PTV_HFILTER2, state->hfilter2); 383 tv_save_filter(dev, NV_PTV_VFILTER, state->vfilter); 384 385 nv_save_ptv(dev, state, 200); 386 nv_save_ptv(dev, state, 204); 387 nv_save_ptv(dev, state, 208); 388 nv_save_ptv(dev, state, 20c); 389 nv_save_ptv(dev, state, 304); 390 nv_save_ptv(dev, state, 500); 391 nv_save_ptv(dev, state, 504); 392 nv_save_ptv(dev, state, 508); 393 nv_save_ptv(dev, state, 600); 394 nv_save_ptv(dev, state, 604); 395 nv_save_ptv(dev, state, 608); 396 nv_save_ptv(dev, state, 60c); 397 nv_save_ptv(dev, state, 610); 398 nv_save_ptv(dev, state, 614); 399} 400 401void nv17_tv_state_load(struct drm_device *dev, struct nv17_tv_state *state) 402{ 403 int i; 404 405 for (i = 0; i < 0x40; i++) 406 nv_write_tv_enc(dev, i, state->tv_enc[i]); 407 408 tv_load_filter(dev, NV_PTV_HFILTER, state->hfilter); 409 tv_load_filter(dev, NV_PTV_HFILTER2, state->hfilter2); 410 tv_load_filter(dev, NV_PTV_VFILTER, state->vfilter); 411 412 nv_load_ptv(dev, state, 200); 413 nv_load_ptv(dev, state, 204); 414 nv_load_ptv(dev, state, 208); 415 nv_load_ptv(dev, state, 20c); 416 nv_load_ptv(dev, state, 304); 417 nv_load_ptv(dev, state, 500); 418 nv_load_ptv(dev, state, 504); 419 nv_load_ptv(dev, state, 508); 420 nv_load_ptv(dev, state, 600); 421 nv_load_ptv(dev, state, 604); 422 nv_load_ptv(dev, state, 608); 423 nv_load_ptv(dev, state, 60c); 424 nv_load_ptv(dev, state, 610); 425 nv_load_ptv(dev, state, 614); 426 427 /* This is required for some settings to kick in. */ 428 nv_write_tv_enc(dev, 0x3e, 1); 429 nv_write_tv_enc(dev, 0x3e, 0); 430} 431 432/* Timings similar to the ones the blob sets */ 433 434struct drm_display_mode nv17_tv_modes[] = { 435 { DRM_MODE("320x200", DRM_MODE_TYPE_DRIVER, 0, 436 320, 344, 392, 560, 0, 200, 200, 202, 220, 0, 437 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC 438 | DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_CLKDIV2) }, 439 { DRM_MODE("320x240", DRM_MODE_TYPE_DRIVER, 0, 440 320, 344, 392, 560, 0, 240, 240, 246, 263, 0, 441 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC 442 | DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_CLKDIV2) }, 443 { DRM_MODE("400x300", DRM_MODE_TYPE_DRIVER, 0, 444 400, 432, 496, 640, 0, 300, 300, 303, 314, 0, 445 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC 446 | DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_CLKDIV2) }, 447 { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 0, 448 640, 672, 768, 880, 0, 480, 480, 492, 525, 0, 449 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, 450 { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 0, 451 720, 752, 872, 960, 0, 480, 480, 493, 525, 0, 452 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, 453 { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 0, 454 720, 776, 856, 960, 0, 576, 576, 588, 597, 0, 455 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, 456 { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 0, 457 800, 840, 920, 1040, 0, 600, 600, 604, 618, 0, 458 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, 459 { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 0, 460 1024, 1064, 1200, 1344, 0, 768, 768, 777, 806, 0, 461 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, 462 {} 463}; 464 465void nv17_tv_update_properties(struct drm_encoder *encoder) 466{ 467 struct drm_device *dev = encoder->dev; 468 struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder); 469 struct nv17_tv_state *regs = &tv_enc->state; 470 struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder); 471 int subconnector = tv_enc->select_subconnector ? 472 tv_enc->select_subconnector : 473 tv_enc->subconnector; 474 475 switch (subconnector) { 476 case DRM_MODE_SUBCONNECTOR_Composite: 477 { 478 regs->ptv_204 = 0x2; 479 480 /* The composite connector may be found on either pin. */ 481 if (tv_enc->pin_mask & 0x4) 482 regs->ptv_204 |= 0x010000; 483 else if (tv_enc->pin_mask & 0x2) 484 regs->ptv_204 |= 0x100000; 485 else 486 regs->ptv_204 |= 0x110000; 487 488 regs->tv_enc[0x7] = 0x10; 489 break; 490 } 491 case DRM_MODE_SUBCONNECTOR_SVIDEO: 492 regs->ptv_204 = 0x11012; 493 regs->tv_enc[0x7] = 0x18; 494 break; 495 496 case DRM_MODE_SUBCONNECTOR_Component: 497 regs->ptv_204 = 0x111333; 498 regs->tv_enc[0x7] = 0x14; 499 break; 500 501 case DRM_MODE_SUBCONNECTOR_SCART: 502 regs->ptv_204 = 0x111012; 503 regs->tv_enc[0x7] = 0x18; 504 break; 505 } 506 507 regs->tv_enc[0x20] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x20], 255, 508 tv_enc->saturation); 509 regs->tv_enc[0x22] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x22], 255, 510 tv_enc->saturation); 511 regs->tv_enc[0x25] = tv_enc->hue * 255 / 100; 512 513 nv_load_ptv(dev, regs, 204); 514 nv_load_tv_enc(dev, regs, 7); 515 nv_load_tv_enc(dev, regs, 20); 516 nv_load_tv_enc(dev, regs, 22); 517 nv_load_tv_enc(dev, regs, 25); 518} 519 520void nv17_tv_update_rescaler(struct drm_encoder *encoder) 521{ 522 struct drm_device *dev = encoder->dev; 523 struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder); 524 struct nv17_tv_state *regs = &tv_enc->state; 525 526 regs->ptv_208 = 0x40 | (calc_overscan(tv_enc->overscan) << 8); 527 528 tv_setup_filter(encoder); 529 530 nv_load_ptv(dev, regs, 208); 531 tv_load_filter(dev, NV_PTV_HFILTER, regs->hfilter); 532 tv_load_filter(dev, NV_PTV_HFILTER2, regs->hfilter2); 533 tv_load_filter(dev, NV_PTV_VFILTER, regs->vfilter); 534} 535 536void nv17_ctv_update_rescaler(struct drm_encoder *encoder) 537{ 538 struct drm_device *dev = encoder->dev; 539 struct drm_nouveau_private *dev_priv = dev->dev_private; 540 struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder); 541 int head = nouveau_crtc(encoder->crtc)->index; 542 struct nv04_crtc_reg *regs = &dev_priv->mode_reg.crtc_reg[head]; 543 struct drm_display_mode *crtc_mode = &encoder->crtc->mode; 544 struct drm_display_mode *output_mode = &get_tv_norm(encoder)->ctv_enc_mode.mode; 545 int overscan, hmargin, vmargin, hratio, vratio; 546 547 /* The rescaler doesn't do the right thing for interlaced modes. */ 548 if (output_mode->flags & DRM_MODE_FLAG_INTERLACE) 549 overscan = 100; 550 else 551 overscan = tv_enc->overscan; 552 553 hmargin = (output_mode->hdisplay - crtc_mode->hdisplay) / 2; 554 vmargin = (output_mode->vdisplay - crtc_mode->vdisplay) / 2; 555 556 hmargin = interpolate(0, min(hmargin, output_mode->hdisplay/20), hmargin, 557 overscan); 558 vmargin = interpolate(0, min(vmargin, output_mode->vdisplay/20), vmargin, 559 overscan); 560 561 hratio = crtc_mode->hdisplay * 0x800 / (output_mode->hdisplay - 2*hmargin); 562 vratio = crtc_mode->vdisplay * 0x800 / (output_mode->vdisplay - 2*vmargin) & ~3; 563 564 regs->fp_horiz_regs[FP_VALID_START] = hmargin; 565 regs->fp_horiz_regs[FP_VALID_END] = output_mode->hdisplay - hmargin - 1; 566 regs->fp_vert_regs[FP_VALID_START] = vmargin; 567 regs->fp_vert_regs[FP_VALID_END] = output_mode->vdisplay - vmargin - 1; 568 569 regs->fp_debug_1 = NV_PRAMDAC_FP_DEBUG_1_YSCALE_TESTMODE_ENABLE | 570 XLATE(vratio, 0, NV_PRAMDAC_FP_DEBUG_1_YSCALE_VALUE) | 571 NV_PRAMDAC_FP_DEBUG_1_XSCALE_TESTMODE_ENABLE | 572 XLATE(hratio, 0, NV_PRAMDAC_FP_DEBUG_1_XSCALE_VALUE); 573 574 NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HVALID_START, 575 regs->fp_horiz_regs[FP_VALID_START]); 576 NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HVALID_END, 577 regs->fp_horiz_regs[FP_VALID_END]); 578 NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_VVALID_START, 579 regs->fp_vert_regs[FP_VALID_START]); 580 NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_VVALID_END, 581 regs->fp_vert_regs[FP_VALID_END]); 582 NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_DEBUG_1, regs->fp_debug_1); 583} 584