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