0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022 #include <drm/drm_connector.h>
0023 #include <drm/drm_mode_config.h>
0024 #include <drm/drm_vblank.h>
0025 #include "nouveau_drv.h"
0026 #include "nouveau_bios.h"
0027 #include "nouveau_connector.h"
0028 #include "head.h"
0029 #include "core.h"
0030 #include "crc.h"
0031
0032 #include <nvif/push507c.h>
0033
0034 #include <nvhw/class/cl907d.h>
0035
0036 int
0037 head907d_or(struct nv50_head *head, struct nv50_head_atom *asyh)
0038 {
0039 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
0040 const int i = head->base.index;
0041 int ret;
0042
0043 if ((ret = PUSH_WAIT(push, 3)))
0044 return ret;
0045
0046 PUSH_MTHD(push, NV907D, HEAD_SET_CONTROL_OUTPUT_RESOURCE(i),
0047 NVVAL(NV907D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, CRC_MODE, asyh->or.crc_raster) |
0048 NVVAL(NV907D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, HSYNC_POLARITY, asyh->or.nhsync) |
0049 NVVAL(NV907D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, VSYNC_POLARITY, asyh->or.nvsync) |
0050 NVVAL(NV907D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, PIXEL_DEPTH, asyh->or.depth),
0051
0052 HEAD_SET_CONTROL(i), 0x31ec6000 | head->base.index << 25 |
0053 NVVAL(NV907D, HEAD_SET_CONTROL, STRUCTURE, asyh->mode.interlace));
0054 return 0;
0055 }
0056
0057 int
0058 head907d_procamp(struct nv50_head *head, struct nv50_head_atom *asyh)
0059 {
0060 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
0061 const int i = head->base.index;
0062 int ret;
0063
0064 if ((ret = PUSH_WAIT(push, 2)))
0065 return ret;
0066
0067 PUSH_MTHD(push, NV907D, HEAD_SET_PROCAMP(i),
0068 NVDEF(NV907D, HEAD_SET_PROCAMP, COLOR_SPACE, RGB) |
0069 NVDEF(NV907D, HEAD_SET_PROCAMP, CHROMA_LPF, AUTO) |
0070 NVVAL(NV907D, HEAD_SET_PROCAMP, SAT_COS, asyh->procamp.sat.cos) |
0071 NVVAL(NV907D, HEAD_SET_PROCAMP, SAT_SINE, asyh->procamp.sat.sin) |
0072 NVDEF(NV907D, HEAD_SET_PROCAMP, DYNAMIC_RANGE, VESA) |
0073 NVDEF(NV907D, HEAD_SET_PROCAMP, RANGE_COMPRESSION, DISABLE));
0074 return 0;
0075 }
0076
0077 static int
0078 head907d_dither(struct nv50_head *head, struct nv50_head_atom *asyh)
0079 {
0080 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
0081 const int i = head->base.index;
0082 int ret;
0083
0084 if ((ret = PUSH_WAIT(push, 2)))
0085 return ret;
0086
0087 PUSH_MTHD(push, NV907D, HEAD_SET_DITHER_CONTROL(i),
0088 NVVAL(NV907D, HEAD_SET_DITHER_CONTROL, ENABLE, asyh->dither.enable) |
0089 NVVAL(NV907D, HEAD_SET_DITHER_CONTROL, BITS, asyh->dither.bits) |
0090 NVVAL(NV907D, HEAD_SET_DITHER_CONTROL, MODE, asyh->dither.mode) |
0091 NVVAL(NV907D, HEAD_SET_DITHER_CONTROL, PHASE, 0));
0092 return 0;
0093 }
0094
0095 int
0096 head907d_ovly(struct nv50_head *head, struct nv50_head_atom *asyh)
0097 {
0098 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
0099 const int i = head->base.index;
0100 u32 bounds = 0;
0101 int ret;
0102
0103 if (asyh->ovly.cpp) {
0104 switch (asyh->ovly.cpp) {
0105 case 8: bounds |= NVDEF(NV907D, HEAD_SET_OVERLAY_USAGE_BOUNDS, PIXEL_DEPTH, BPP_64); break;
0106 case 4: bounds |= NVDEF(NV907D, HEAD_SET_OVERLAY_USAGE_BOUNDS, PIXEL_DEPTH, BPP_32); break;
0107 case 2: bounds |= NVDEF(NV907D, HEAD_SET_OVERLAY_USAGE_BOUNDS, PIXEL_DEPTH, BPP_16); break;
0108 default:
0109 WARN_ON(1);
0110 break;
0111 }
0112 bounds |= NVDEF(NV907D, HEAD_SET_OVERLAY_USAGE_BOUNDS, USABLE, TRUE);
0113 } else {
0114 bounds |= NVDEF(NV907D, HEAD_SET_OVERLAY_USAGE_BOUNDS, PIXEL_DEPTH, BPP_16);
0115 }
0116
0117 if ((ret = PUSH_WAIT(push, 2)))
0118 return ret;
0119
0120 PUSH_MTHD(push, NV907D, HEAD_SET_OVERLAY_USAGE_BOUNDS(i), bounds);
0121 return 0;
0122 }
0123
0124 static int
0125 head907d_base(struct nv50_head *head, struct nv50_head_atom *asyh)
0126 {
0127 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
0128 const int i = head->base.index;
0129 u32 bounds = 0;
0130 int ret;
0131
0132 if (asyh->base.cpp) {
0133 switch (asyh->base.cpp) {
0134 case 8: bounds |= NVDEF(NV907D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_64); break;
0135 case 4: bounds |= NVDEF(NV907D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_32); break;
0136 case 2: bounds |= NVDEF(NV907D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_16); break;
0137 case 1: bounds |= NVDEF(NV907D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_8); break;
0138 default:
0139 WARN_ON(1);
0140 break;
0141 }
0142 bounds |= NVDEF(NV907D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, USABLE, TRUE);
0143 }
0144
0145 if ((ret = PUSH_WAIT(push, 2)))
0146 return ret;
0147
0148 PUSH_MTHD(push, NV907D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS(i), bounds);
0149 return 0;
0150 }
0151
0152 int
0153 head907d_curs_clr(struct nv50_head *head)
0154 {
0155 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
0156 const int i = head->base.index;
0157 int ret;
0158
0159 if ((ret = PUSH_WAIT(push, 4)))
0160 return ret;
0161
0162 PUSH_MTHD(push, NV907D, HEAD_SET_CONTROL_CURSOR(i),
0163 NVDEF(NV907D, HEAD_SET_CONTROL_CURSOR, ENABLE, DISABLE) |
0164 NVDEF(NV907D, HEAD_SET_CONTROL_CURSOR, FORMAT, A8R8G8B8) |
0165 NVDEF(NV907D, HEAD_SET_CONTROL_CURSOR, SIZE, W64_H64));
0166
0167 PUSH_MTHD(push, NV907D, HEAD_SET_CONTEXT_DMA_CURSOR(i), 0x00000000);
0168 return 0;
0169 }
0170
0171 int
0172 head907d_curs_set(struct nv50_head *head, struct nv50_head_atom *asyh)
0173 {
0174 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
0175 const int i = head->base.index;
0176 int ret;
0177
0178 if ((ret = PUSH_WAIT(push, 5)))
0179 return ret;
0180
0181 PUSH_MTHD(push, NV907D, HEAD_SET_CONTROL_CURSOR(i),
0182 NVDEF(NV907D, HEAD_SET_CONTROL_CURSOR, ENABLE, ENABLE) |
0183 NVVAL(NV907D, HEAD_SET_CONTROL_CURSOR, FORMAT, asyh->curs.format) |
0184 NVVAL(NV907D, HEAD_SET_CONTROL_CURSOR, SIZE, asyh->curs.layout) |
0185 NVVAL(NV907D, HEAD_SET_CONTROL_CURSOR, HOT_SPOT_X, 0) |
0186 NVVAL(NV907D, HEAD_SET_CONTROL_CURSOR, HOT_SPOT_Y, 0) |
0187 NVDEF(NV907D, HEAD_SET_CONTROL_CURSOR, COMPOSITION, ALPHA_BLEND),
0188
0189 HEAD_SET_OFFSET_CURSOR(i), asyh->curs.offset >> 8);
0190
0191 PUSH_MTHD(push, NV907D, HEAD_SET_CONTEXT_DMA_CURSOR(i), asyh->curs.handle);
0192 return 0;
0193 }
0194
0195 int
0196 head907d_core_clr(struct nv50_head *head)
0197 {
0198 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
0199 const int i = head->base.index;
0200 int ret;
0201
0202 if ((ret = PUSH_WAIT(push, 2)))
0203 return ret;
0204
0205 PUSH_MTHD(push, NV907D, HEAD_SET_CONTEXT_DMAS_ISO(i), 0x00000000);
0206 return 0;
0207 }
0208
0209 int
0210 head907d_core_set(struct nv50_head *head, struct nv50_head_atom *asyh)
0211 {
0212 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
0213 const int i = head->base.index;
0214 int ret;
0215
0216 if ((ret = PUSH_WAIT(push, 9)))
0217 return ret;
0218
0219 PUSH_MTHD(push, NV907D, HEAD_SET_OFFSET(i),
0220 NVVAL(NV907D, HEAD_SET_OFFSET, ORIGIN, asyh->core.offset >> 8));
0221
0222 PUSH_MTHD(push, NV907D, HEAD_SET_SIZE(i),
0223 NVVAL(NV907D, HEAD_SET_SIZE, WIDTH, asyh->core.w) |
0224 NVVAL(NV907D, HEAD_SET_SIZE, HEIGHT, asyh->core.h),
0225
0226 HEAD_SET_STORAGE(i),
0227 NVVAL(NV907D, HEAD_SET_STORAGE, BLOCK_HEIGHT, asyh->core.blockh) |
0228 NVVAL(NV907D, HEAD_SET_STORAGE, PITCH, asyh->core.pitch >> 8) |
0229 NVVAL(NV907D, HEAD_SET_STORAGE, PITCH, asyh->core.blocks) |
0230 NVVAL(NV907D, HEAD_SET_STORAGE, MEMORY_LAYOUT, asyh->core.layout),
0231
0232 HEAD_SET_PARAMS(i),
0233 NVVAL(NV907D, HEAD_SET_PARAMS, FORMAT, asyh->core.format) |
0234 NVDEF(NV907D, HEAD_SET_PARAMS, SUPER_SAMPLE, X1_AA) |
0235 NVDEF(NV907D, HEAD_SET_PARAMS, GAMMA, LINEAR),
0236
0237 HEAD_SET_CONTEXT_DMAS_ISO(i),
0238 NVVAL(NV907D, HEAD_SET_CONTEXT_DMAS_ISO, HANDLE, asyh->core.handle));
0239
0240 PUSH_MTHD(push, NV907D, HEAD_SET_VIEWPORT_POINT_IN(i),
0241 NVVAL(NV907D, HEAD_SET_VIEWPORT_POINT_IN, X, asyh->core.x) |
0242 NVVAL(NV907D, HEAD_SET_VIEWPORT_POINT_IN, Y, asyh->core.y));
0243 return 0;
0244 }
0245
0246 int
0247 head907d_olut_clr(struct nv50_head *head)
0248 {
0249 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
0250 const int i = head->base.index;
0251 int ret;
0252
0253 if ((ret = PUSH_WAIT(push, 4)))
0254 return ret;
0255
0256 PUSH_MTHD(push, NV907D, HEAD_SET_OUTPUT_LUT_LO(i),
0257 NVDEF(NV907D, HEAD_SET_OUTPUT_LUT_LO, ENABLE, DISABLE));
0258
0259 PUSH_MTHD(push, NV907D, HEAD_SET_CONTEXT_DMA_LUT(i), 0x00000000);
0260 return 0;
0261 }
0262
0263 int
0264 head907d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
0265 {
0266 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
0267 const int i = head->base.index;
0268 int ret;
0269
0270 if ((ret = PUSH_WAIT(push, 5)))
0271 return ret;
0272
0273 PUSH_MTHD(push, NV907D, HEAD_SET_OUTPUT_LUT_LO(i),
0274 NVDEF(NV907D, HEAD_SET_OUTPUT_LUT_LO, ENABLE, ENABLE) |
0275 NVVAL(NV907D, HEAD_SET_OUTPUT_LUT_LO, MODE, asyh->olut.mode) |
0276 NVDEF(NV907D, HEAD_SET_OUTPUT_LUT_LO, NEVER_YIELD_TO_BASE, DISABLE),
0277
0278 HEAD_SET_OUTPUT_LUT_HI(i),
0279 NVVAL(NV907D, HEAD_SET_OUTPUT_LUT_HI, ORIGIN, asyh->olut.offset >> 8));
0280
0281 PUSH_MTHD(push, NV907D, HEAD_SET_CONTEXT_DMA_LUT(i), asyh->olut.handle);
0282 return 0;
0283 }
0284
0285 void
0286 head907d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem)
0287 {
0288 for (; size--; in++, mem += 8) {
0289 writew(drm_color_lut_extract(in-> red, 14) + 0x6000, mem + 0);
0290 writew(drm_color_lut_extract(in->green, 14) + 0x6000, mem + 2);
0291 writew(drm_color_lut_extract(in-> blue, 14) + 0x6000, mem + 4);
0292 }
0293
0294
0295
0296
0297 writew(readw(mem - 8), mem + 0);
0298 writew(readw(mem - 6), mem + 2);
0299 writew(readw(mem - 4), mem + 4);
0300 }
0301
0302 bool
0303 head907d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size)
0304 {
0305 if (size != 256 && size != 1024)
0306 return false;
0307
0308 if (size == 1024)
0309 asyh->olut.mode = NV907D_HEAD_SET_OUTPUT_LUT_LO_MODE_INTERPOLATE_1025_UNITY_RANGE;
0310 else
0311 asyh->olut.mode = NV907D_HEAD_SET_OUTPUT_LUT_LO_MODE_INTERPOLATE_257_UNITY_RANGE;
0312
0313 asyh->olut.load = head907d_olut_load;
0314 return true;
0315 }
0316
0317 bool head907d_ilut_check(int size)
0318 {
0319 return size == 256 || size == 1024;
0320 }
0321
0322 int
0323 head907d_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
0324 {
0325 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
0326 struct nv50_head_mode *m = &asyh->mode;
0327 const int i = head->base.index;
0328 int ret;
0329
0330 if ((ret = PUSH_WAIT(push, 13)))
0331 return ret;
0332
0333 PUSH_MTHD(push, NV907D, HEAD_SET_OVERSCAN_COLOR(i),
0334 NVVAL(NV907D, HEAD_SET_OVERSCAN_COLOR, RED, 0) |
0335 NVVAL(NV907D, HEAD_SET_OVERSCAN_COLOR, GRN, 0) |
0336 NVVAL(NV907D, HEAD_SET_OVERSCAN_COLOR, BLU, 0),
0337
0338 HEAD_SET_RASTER_SIZE(i),
0339 NVVAL(NV907D, HEAD_SET_RASTER_SIZE, WIDTH, m->h.active) |
0340 NVVAL(NV907D, HEAD_SET_RASTER_SIZE, HEIGHT, m->v.active),
0341
0342 HEAD_SET_RASTER_SYNC_END(i),
0343 NVVAL(NV907D, HEAD_SET_RASTER_SYNC_END, X, m->h.synce) |
0344 NVVAL(NV907D, HEAD_SET_RASTER_SYNC_END, Y, m->v.synce),
0345
0346 HEAD_SET_RASTER_BLANK_END(i),
0347 NVVAL(NV907D, HEAD_SET_RASTER_BLANK_END, X, m->h.blanke) |
0348 NVVAL(NV907D, HEAD_SET_RASTER_BLANK_END, Y, m->v.blanke),
0349
0350 HEAD_SET_RASTER_BLANK_START(i),
0351 NVVAL(NV907D, HEAD_SET_RASTER_BLANK_START, X, m->h.blanks) |
0352 NVVAL(NV907D, HEAD_SET_RASTER_BLANK_START, Y, m->v.blanks),
0353
0354 HEAD_SET_RASTER_VERT_BLANK2(i),
0355 NVVAL(NV907D, HEAD_SET_RASTER_VERT_BLANK2, YSTART, m->v.blank2s) |
0356 NVVAL(NV907D, HEAD_SET_RASTER_VERT_BLANK2, YEND, m->v.blank2e));
0357
0358 PUSH_MTHD(push, NV907D, HEAD_SET_DEFAULT_BASE_COLOR(i),
0359 NVVAL(NV907D, HEAD_SET_DEFAULT_BASE_COLOR, RED, 0) |
0360 NVVAL(NV907D, HEAD_SET_DEFAULT_BASE_COLOR, GREEN, 0) |
0361 NVVAL(NV907D, HEAD_SET_DEFAULT_BASE_COLOR, BLUE, 0));
0362
0363 PUSH_MTHD(push, NV907D, HEAD_SET_PIXEL_CLOCK_FREQUENCY(i),
0364 NVVAL(NV907D, HEAD_SET_PIXEL_CLOCK_FREQUENCY, HERTZ, m->clock * 1000) |
0365 NVDEF(NV907D, HEAD_SET_PIXEL_CLOCK_FREQUENCY, ADJ1000DIV1001, FALSE),
0366
0367 HEAD_SET_PIXEL_CLOCK_CONFIGURATION(i),
0368 NVDEF(NV907D, HEAD_SET_PIXEL_CLOCK_CONFIGURATION, MODE, CLK_CUSTOM) |
0369 NVDEF(NV907D, HEAD_SET_PIXEL_CLOCK_CONFIGURATION, NOT_DRIVER, FALSE) |
0370 NVDEF(NV907D, HEAD_SET_PIXEL_CLOCK_CONFIGURATION, ENABLE_HOPPING, FALSE),
0371
0372 HEAD_SET_PIXEL_CLOCK_FREQUENCY_MAX(i),
0373 NVVAL(NV907D, HEAD_SET_PIXEL_CLOCK_FREQUENCY_MAX, HERTZ, m->clock * 1000) |
0374 NVDEF(NV907D, HEAD_SET_PIXEL_CLOCK_FREQUENCY_MAX, ADJ1000DIV1001, FALSE));
0375 return 0;
0376 }
0377
0378 int
0379 head907d_view(struct nv50_head *head, struct nv50_head_atom *asyh)
0380 {
0381 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
0382 const int i = head->base.index;
0383 int ret;
0384
0385 if ((ret = PUSH_WAIT(push, 8)))
0386 return ret;
0387
0388 PUSH_MTHD(push, NV907D, HEAD_SET_CONTROL_OUTPUT_SCALER(i),
0389 NVDEF(NV907D, HEAD_SET_CONTROL_OUTPUT_SCALER, VERTICAL_TAPS, TAPS_1) |
0390 NVDEF(NV907D, HEAD_SET_CONTROL_OUTPUT_SCALER, HORIZONTAL_TAPS, TAPS_1) |
0391 NVVAL(NV907D, HEAD_SET_CONTROL_OUTPUT_SCALER, HRESPONSE_BIAS, 0) |
0392 NVVAL(NV907D, HEAD_SET_CONTROL_OUTPUT_SCALER, VRESPONSE_BIAS, 0));
0393
0394 PUSH_MTHD(push, NV907D, HEAD_SET_VIEWPORT_SIZE_IN(i),
0395 NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_IN, WIDTH, asyh->view.iW) |
0396 NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_IN, HEIGHT, asyh->view.iH));
0397
0398 PUSH_MTHD(push, NV907D, HEAD_SET_VIEWPORT_SIZE_OUT(i),
0399 NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_OUT, WIDTH, asyh->view.oW) |
0400 NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_OUT, HEIGHT, asyh->view.oH),
0401
0402 HEAD_SET_VIEWPORT_SIZE_OUT_MIN(i),
0403 NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_OUT_MIN, WIDTH, asyh->view.oW) |
0404 NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_OUT_MIN, HEIGHT, asyh->view.oH),
0405
0406 HEAD_SET_VIEWPORT_SIZE_OUT_MAX(i),
0407 NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_OUT_MAX, WIDTH, asyh->view.oW) |
0408 NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_OUT_MAX, HEIGHT, asyh->view.oH));
0409 return 0;
0410 }
0411
0412 const struct nv50_head_func
0413 head907d = {
0414 .view = head907d_view,
0415 .mode = head907d_mode,
0416 .olut = head907d_olut,
0417 .ilut_check = head907d_ilut_check,
0418 .olut_size = 1024,
0419 .olut_set = head907d_olut_set,
0420 .olut_clr = head907d_olut_clr,
0421 .core_calc = head507d_core_calc,
0422 .core_set = head907d_core_set,
0423 .core_clr = head907d_core_clr,
0424 .curs_layout = head507d_curs_layout,
0425 .curs_format = head507d_curs_format,
0426 .curs_set = head907d_curs_set,
0427 .curs_clr = head907d_curs_clr,
0428 .base = head907d_base,
0429 .ovly = head907d_ovly,
0430 .dither = head907d_dither,
0431 .procamp = head907d_procamp,
0432 .or = head907d_or,
0433 };