1// Copyright 2017 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#pragma once
6
7#include <assert.h>
8#include <ddk/protocol/display-controller.h>
9#include <ddk/protocol/intel-gpu-core.h>
10#include <hwreg/bitfields.h>
11#include <zircon/pixelformat.h>
12
13namespace registers {
14
15// Number of pipes that the hardware provides.
16static constexpr uint32_t kPipeCount = 3;
17
18enum Pipe { PIPE_A, PIPE_B, PIPE_C, PIPE_INVALID };
19
20static const Pipe kPipes[kPipeCount] = {
21    PIPE_A, PIPE_B, PIPE_C,
22};
23
24static constexpr uint32_t kImagePlaneCount = 3;
25static constexpr uint32_t kCursorPlane = 2;
26
27// PIPE_SRCSZ
28class PipeSourceSize : public hwreg::RegisterBase<PipeSourceSize, uint32_t> {
29public:
30    static constexpr uint32_t kBaseAddr = 0x6001c;
31
32    DEF_FIELD(28, 16, horizontal_source_size);
33    DEF_FIELD(11, 0, vertical_source_size);
34};
35
36// PIPE_BOTTOM_COLOR
37class PipeBottomColor : public hwreg::RegisterBase<PipeBottomColor, uint32_t> {
38public:
39    static constexpr uint32_t kBaseAddr = 0x70034;
40
41    DEF_BIT(31, gamma_enable);
42    DEF_BIT(30, csc_enable);
43    DEF_FIELD(29, 20, r);
44    DEF_FIELD(19, 10, g);
45    DEF_FIELD(9, 0, b);
46};
47
48
49// PLANE_SURF
50class PlaneSurface : public hwreg::RegisterBase<PlaneSurface, uint32_t> {
51public:
52    static constexpr uint32_t kBaseAddr = 0x7019c;
53
54    // This field omits the lower 12 bits of the address, so the address
55    // must be 4k-aligned.
56    static constexpr uint32_t kPageShift = 12;
57    DEF_FIELD(31, 12, surface_base_addr);
58    static constexpr uint32_t kRShiftCount = 12;
59    static constexpr uint32_t kLinearAlignment = 256 * 1024;
60    static constexpr uint32_t kXTilingAlignment = 256 * 1024;
61    static constexpr uint32_t kYTilingAlignment = 1024 * 1024;
62
63    DEF_BIT(3, ring_flip_source);
64};
65
66// PLANE_SURFLIVE
67class PlaneSurfaceLive : public hwreg::RegisterBase<PlaneSurfaceLive, uint32_t> {
68public:
69    static constexpr uint32_t kBaseAddr = 0x701ac;
70
71    // This field omits the lower 12 bits of the address, so the address
72    // must be 4k-aligned.
73    static constexpr uint32_t kPageShift = 12;
74    DEF_FIELD(31, 12, surface_base_addr);
75};
76
77// PLANE_STRIDE
78class PlaneSurfaceStride : public hwreg::RegisterBase<PlaneSurfaceStride, uint32_t> {
79public:
80    static constexpr uint32_t kBaseAddr = 0x70188;
81
82    DEF_FIELD(9, 0, stride);
83};
84
85// PLANE_SIZE
86class PlaneSurfaceSize : public hwreg::RegisterBase<PlaneSurfaceSize, uint32_t> {
87public:
88    static constexpr uint32_t kBaseAddr = 0x70190;
89
90    DEF_FIELD(27, 16, height_minus_1);
91    DEF_FIELD(12, 0, width_minus_1);
92};
93
94// PLANE_CTL
95class PlaneControl : public hwreg::RegisterBase<PlaneControl, uint32_t> {
96public:
97    static constexpr uint32_t kBaseAddr = 0x70180;
98
99    DEF_BIT(31, plane_enable);
100    DEF_BIT(30, pipe_gamma_enable);
101    DEF_BIT(29, remove_yuv_offset);
102    DEF_BIT(28, yuv_range_correction_disable);
103
104    DEF_FIELD(27, 24, source_pixel_format);
105    static constexpr uint32_t kFormatRgb8888 = 4;
106
107    DEF_BIT(23, pipe_csc_enable);
108    DEF_FIELD(22, 21, key_enable);
109    DEF_BIT(20, rgb_color_order);
110    DEF_BIT(19, plane_yuv_to_rgb_csc_dis);
111    DEF_BIT(18, plane_yuv_to_rgb_csc_format);
112    DEF_FIELD(17, 16, yuv_422_byte_order);
113    DEF_BIT(15, render_decompression);
114    DEF_BIT(14, trickle_feed_enable);
115    DEF_BIT(13, plane_gamma_disable);
116
117    DEF_FIELD(12, 10, tiled_surface);
118    static constexpr uint32_t kLinear = 0;
119    static constexpr uint32_t kTilingX = 1;
120    static constexpr uint32_t kTilingYLegacy = 4;
121    static constexpr uint32_t kTilingYF = 5;
122
123    DEF_BIT(9, async_address_update_enable);
124    DEF_FIELD(7, 6, stereo_surface_vblank_mask);
125    DEF_FIELD(5, 4, alpha_mode);
126    static constexpr uint32_t kAlphaDisable = 0;
127    static constexpr uint32_t kAlphaPreMultiply = 2;
128    static constexpr uint32_t kAlphaHwMultiply = 3;
129
130
131    DEF_BIT(3, allow_double_buffer_update_disable);
132    DEF_FIELD(1, 0, plane_rotation);
133    static constexpr uint32_t kIdentity = 0;
134    static constexpr uint32_t k90deg = 1;
135    static constexpr uint32_t k180deg = 2;
136    static constexpr uint32_t k270deg = 3;
137};
138
139// PLANE_BUF_CFG
140class PlaneBufCfg : public hwreg::RegisterBase<PlaneBufCfg, uint32_t> {
141public:
142    static constexpr uint32_t kBaseAddr = 0x7017c;
143    static constexpr uint32_t kBufferCount = 892;
144
145    DEF_FIELD(25, 16, buffer_end);
146    DEF_FIELD(9, 0, buffer_start);
147};
148
149// PLANE_WM
150class PlaneWm : public hwreg::RegisterBase<PlaneWm, uint32_t> {
151public:
152    static constexpr uint32_t kBaseAddr = 0x70140;
153
154    DEF_BIT(31, enable);
155    DEF_FIELD(18, 14, lines);
156    DEF_FIELD(9, 0, blocks);
157};
158
159// PLANE_KEYMSK
160class PlaneKeyMask : public hwreg::RegisterBase<PlaneKeyMask, uint32_t> {
161public:
162    static constexpr uint32_t kBaseAddr = 0x70198;
163
164    DEF_BIT(31, plane_alpha_enable);
165};
166
167// PLANE_KEYMAX
168class PlaneKeyMax : public hwreg::RegisterBase<PlaneKeyMax, uint32_t> {
169public:
170    static constexpr uint32_t kBaseAddr = 0x701a0;
171
172    DEF_FIELD(31, 24, plane_alpha_value);
173};
174
175// PLANE_OFFSET
176class PlaneOffset : public hwreg::RegisterBase<PlaneOffset, uint32_t> {
177public:
178    static constexpr uint32_t kBaseAddr = 0x701a4;
179
180    DEF_FIELD(28, 16, start_y);
181    DEF_FIELD(12, 0, start_x);
182};
183
184// PLANE_POS
185class PlanePosition : public hwreg::RegisterBase<PlanePosition, uint32_t> {
186public:
187    static constexpr uint32_t kBaseAddr = 0x7018c;
188
189    DEF_FIELD(28, 16, y_pos);
190    DEF_FIELD(12, 0, x_pos);
191};
192
193// PS_CTRL
194class PipeScalerCtrl : public hwreg::RegisterBase<PipeScalerCtrl, uint32_t> {
195public:
196    static constexpr uint32_t kBaseAddr = 0x68180;
197
198    DEF_BIT(31, enable);
199    DEF_FIELD(29, 28, mode);
200    static constexpr uint32_t kDynamic = 0;
201    static constexpr uint32_t k7x5 = 1;
202
203    DEF_FIELD(27, 25, binding);
204    static constexpr uint32_t kPipeScaler = 0;
205    static constexpr uint32_t kPlane1 = 1;
206    static constexpr uint32_t kPlane2 = 2;
207    static constexpr uint32_t kPlane3 = 3;
208
209    DEF_FIELD(24, 23, filter_select);
210    static constexpr uint32_t kMedium = 0;
211    static constexpr uint32_t kEdgeEnhance = 2;
212    static constexpr uint32_t kBilienar = 3;
213
214    static constexpr uint32_t kMinSrcSizePx = 8;
215    static constexpr uint32_t kMaxSrcWidthPx = 4096;
216    static constexpr uint32_t kPipeABScalersAvailable = 2;
217    static constexpr uint32_t kPipeCScalersAvailable = 1;
218    static constexpr float k7x5MaxRatio = 2.99f;
219    static constexpr float kDynamicMaxRatio = 2.99f;
220    static constexpr float kDynamicMaxVerticalRatio2049 = 1.99f;
221};
222
223// PS_WIN_POS
224class PipeScalerWinPosition : public hwreg::RegisterBase<PipeScalerWinPosition, uint32_t> {
225public:
226    static constexpr uint32_t kBaseAddr = 0x68170;
227
228    DEF_FIELD(28, 16, x_pos);
229    DEF_FIELD(11, 0, y_pos);
230};
231
232// PS_WIN_SIZE
233class PipeScalerWinSize : public hwreg::RegisterBase<PipeScalerWinSize, uint32_t> {
234public:
235    static constexpr uint32_t kBaseAddr = 0x68174;
236
237    DEF_FIELD(28, 16, x_size);
238    DEF_FIELD(11, 0, y_size);
239};
240
241// DE_PIPE_INTERRUPT
242class PipeDeInterrupt : public hwreg::RegisterBase<PipeDeInterrupt, uint32_t> {
243public:
244    DEF_BIT(1, vsync);
245};
246
247// CUR_BASE
248class CursorBase : public hwreg::RegisterBase<CursorBase, uint32_t> {
249public:
250    static constexpr uint32_t kBaseAddr = 0x70084;
251
252    DEF_FIELD(31, 12, cursor_base);
253    // This field omits the lower 12 bits of the address, so the address
254    // must be 4k-aligned.
255    static constexpr uint32_t kPageShift = 12;
256};
257
258// CUR_CTL
259class CursorCtrl : public hwreg::RegisterBase<CursorCtrl, uint32_t> {
260public:
261    static constexpr uint32_t kBaseAddr = 0x70080;
262
263    DEF_BIT(24, pipe_csc_enable);
264    DEF_FIELD(5, 0, mode_select);
265    static constexpr uint32_t kDisabled = 0;
266    static constexpr uint32_t kArgb128x128 = 34;
267    static constexpr uint32_t kArgb256x256 = 35;
268    static constexpr uint32_t kArgb64x64 = 39;
269};
270
271// CUR_POS
272class CursorPos : public hwreg::RegisterBase<CursorPos, uint32_t> {
273public:
274    static constexpr uint32_t kBaseAddr = 0x70088;
275
276    DEF_BIT(31, y_sign);
277    DEF_FIELD(27, 16, y_pos);
278    DEF_BIT(15, x_sign);
279    DEF_FIELD(12, 0, x_pos);
280};
281
282// CUR_SURFLIVE
283class CursorSurfaceLive : public hwreg::RegisterBase<CursorSurfaceLive, uint32_t> {
284public:
285    static constexpr uint32_t kBaseAddr = 0x700ac;
286
287    static constexpr uint32_t kPageShift = 12;
288    DEF_FIELD(31, 12, surface_base_addr);
289};
290
291// CSC_COEFF
292class CscCoeff : public hwreg::RegisterBase<CscCoeff, uint32_t> {
293public:
294    static constexpr uint32_t kBaseAddr = 0x49010;
295
296    hwreg::BitfieldRef<uint32_t> coefficient(uint32_t i, uint32_t j) {
297        ZX_DEBUG_ASSERT(i < 3 && j < 3);
298        uint32_t bit = 16 - ((j % 2) * 16);
299        return hwreg::BitfieldRef<uint32_t>(reg_value_ptr(), bit + 15, bit);
300    }
301};
302
303class CscCoeffFormat : public hwreg::RegisterBase<CscCoeffFormat, uint16_t> {
304public:
305    DEF_BIT(15, sign);
306    DEF_FIELD(14, 12, exponent);
307    static constexpr uint16_t kExponent0125 = 3;
308    static constexpr uint16_t kExponent025 = 2;
309    static constexpr uint16_t kExponent05 = 1;
310    static constexpr uint16_t kExponent1 = 0;
311    static constexpr uint16_t kExponent2 = 7;
312    static constexpr uint16_t kExponent4 = 6;
313    DEF_FIELD(11, 3, mantissa);
314};
315
316// CSC_MODE
317class CscMode : public hwreg::RegisterBase<CscMode, uint32_t> {
318public:
319    static constexpr uint32_t kBaseAddr = 0x49028;
320};
321
322// CSC_POSTOFF / CSC_PREOFF
323class CscOffset : public hwreg::RegisterBase<CscOffset, uint32_t> {
324public:
325    static constexpr uint32_t kPostOffsetBaseAddr = 0x49040;
326    static constexpr uint32_t kPreOffsetBaseAddr = 0x49030;
327
328    DEF_BIT(12, sign);
329    DEF_FIELD(11, 0, magnitude);
330};
331
332// An instance of PipeRegs represents the registers for a particular pipe.
333class PipeRegs {
334public:
335    static constexpr uint32_t kStatusReg = 0x44400;
336    static constexpr uint32_t kMaskReg = 0x44404;
337    static constexpr uint32_t kIdentityReg = 0x44408;
338    static constexpr uint32_t kEnableReg = 0x4440c;
339
340    PipeRegs(Pipe pipe) : pipe_(pipe) { }
341
342    hwreg::RegisterAddr<registers::PipeSourceSize> PipeSourceSize() {
343        return GetReg<registers::PipeSourceSize>();
344    }
345    hwreg::RegisterAddr<registers::PipeBottomColor> PipeBottomColor() {
346        return GetReg<registers::PipeBottomColor>();
347    }
348
349    hwreg::RegisterAddr<registers::PlaneSurface> PlaneSurface(int32_t plane_num) {
350        return GetPlaneReg<registers::PlaneSurface>(plane_num);
351    }
352    hwreg::RegisterAddr<registers::PlaneSurfaceLive> PlaneSurfaceLive(int32_t plane_num) {
353        return GetPlaneReg<registers::PlaneSurfaceLive>(plane_num);
354    }
355    hwreg::RegisterAddr<registers::PlaneSurfaceStride> PlaneSurfaceStride(int32_t plane_num) {
356        return GetPlaneReg<registers::PlaneSurfaceStride>(plane_num);
357    }
358    hwreg::RegisterAddr<registers::PlaneSurfaceSize> PlaneSurfaceSize(int32_t plane_num) {
359        return GetPlaneReg<registers::PlaneSurfaceSize>(plane_num);
360    }
361    hwreg::RegisterAddr<registers::PlaneControl> PlaneControl(int32_t plane_num) {
362        return GetPlaneReg<registers::PlaneControl>(plane_num);
363    }
364    hwreg::RegisterAddr<registers::PlaneOffset> PlaneOffset(int32_t plane_num) {
365        return GetPlaneReg<registers::PlaneOffset>(plane_num);
366    }
367    hwreg::RegisterAddr<registers::PlanePosition> PlanePosition(int32_t plane_num) {
368        return GetPlaneReg<registers::PlanePosition>(plane_num);
369    }
370    // 0 == cursor, 1-3 are regular planes
371    hwreg::RegisterAddr<registers::PlaneBufCfg> PlaneBufCfg(int plane) {
372        return hwreg::RegisterAddr<registers::PlaneBufCfg>(
373                PlaneBufCfg::kBaseAddr + 0x1000 * pipe_ + 0x100 * plane);
374    }
375
376    hwreg::RegisterAddr<registers::PlaneWm>PlaneWatermark(int plane, int wm_num) {
377        return hwreg::RegisterAddr<PlaneWm>(
378                PlaneWm::kBaseAddr + 0x1000 * pipe_ + 0x100 * plane + 4 * wm_num);
379    }
380
381    hwreg::RegisterAddr<registers::PlaneKeyMask> PlaneKeyMask(int32_t plane_num) {
382        return GetPlaneReg<registers::PlaneKeyMask>(plane_num);
383    }
384    hwreg::RegisterAddr<registers::PlaneKeyMax> PlaneKeyMax(int32_t plane_num) {
385        return GetPlaneReg<registers::PlaneKeyMax>(plane_num);
386    }
387
388    hwreg::RegisterAddr<registers::PipeScalerCtrl> PipeScalerCtrl(int num) {
389        return hwreg::RegisterAddr<registers::PipeScalerCtrl>(
390                PipeScalerCtrl::kBaseAddr + 0x800 * pipe_ + num * 0x100);
391    }
392
393    hwreg::RegisterAddr<registers::PipeScalerWinPosition> PipeScalerWinPosition(int num) {
394        return hwreg::RegisterAddr<registers::PipeScalerWinPosition>(
395                PipeScalerWinPosition::kBaseAddr + 0x800 * pipe_ + num * 0x100);
396    }
397
398    hwreg::RegisterAddr<registers::PipeScalerWinSize> PipeScalerWinSize(int num) {
399        return hwreg::RegisterAddr<registers::PipeScalerWinSize>(
400                PipeScalerWinSize::kBaseAddr + 0x800 * pipe_ + num * 0x100);
401    }
402
403    hwreg::RegisterAddr<registers::PipeDeInterrupt> PipeDeInterrupt(uint32_t type) {
404        return hwreg::RegisterAddr<registers::PipeDeInterrupt>(type + 0x10 * pipe_);
405    }
406
407    hwreg::RegisterAddr<registers::CursorBase> CursorBase() {
408        return GetReg<registers::CursorBase>();
409    }
410
411    hwreg::RegisterAddr<registers::CursorCtrl> CursorCtrl() {
412        return GetReg<registers::CursorCtrl>();
413    }
414
415    hwreg::RegisterAddr<registers::CursorPos> CursorPos() {
416        return GetReg<registers::CursorPos>();
417    }
418
419    hwreg::RegisterAddr<registers::CursorSurfaceLive> CursorSurfaceLive() {
420        return GetReg<registers::CursorSurfaceLive>();
421    }
422
423    hwreg::RegisterAddr<registers::CscCoeff> CscCoeff(uint32_t i, uint32_t j) {
424        ZX_DEBUG_ASSERT(i < 3 && j < 3);
425        uint32_t base = registers::CscCoeff::kBaseAddr + 4 * ((i * 2) + (j == 2 ? 1 : 0));
426        return GetCscReg<registers::CscCoeff>(base);
427    }
428
429    hwreg::RegisterAddr<registers::CscMode> CscMode() {
430        return GetCscReg<registers::CscMode>(registers::CscMode::kBaseAddr);
431    }
432
433    hwreg::RegisterAddr<registers::CscOffset> CscOffset(bool preoffset, uint32_t component_idx) {
434        uint32_t base = (4 * component_idx) + (preoffset ?
435            registers::CscOffset::kPreOffsetBaseAddr : registers::CscOffset::kPostOffsetBaseAddr);
436        return GetCscReg<registers::CscOffset>(base);
437    }
438
439private:
440    template <class RegType> hwreg::RegisterAddr<RegType> GetReg() {
441        return hwreg::RegisterAddr<RegType>(RegType::kBaseAddr + 0x1000 * pipe_);
442    }
443
444    template <class RegType> hwreg::RegisterAddr<RegType> GetPlaneReg(int32_t plane) {
445        return hwreg::RegisterAddr<RegType>(RegType::kBaseAddr + 0x1000 * pipe_ + 0x100 * plane);
446    }
447
448    template <class RegType> hwreg::RegisterAddr<RegType> GetCscReg(uint32_t base) {
449        return hwreg::RegisterAddr<RegType>(base + 0x100 * pipe_);
450    }
451
452    Pipe pipe_;
453};
454
455// Struct of registers which arm double buffered registers
456typedef struct pipe_arming_regs {
457    uint32_t csc_mode;
458    uint32_t pipe_bottom_color;
459    uint32_t cur_base;
460    uint32_t cur_pos;
461    uint32_t plane_surf[kImagePlaneCount];
462    uint32_t ps_win_sz[2];
463} pipe_arming_regs_t;
464
465} // namespace registers
466