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