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/intelgpucore.h>
10 #include <hwreg/bitfields.h>
11 #include <zircon/pixelformat.h>
12 
13 namespace registers {
14 
15 // Number of pipes that the hardware provides.
16 static constexpr uint32_t kPipeCount = 3;
17 
18 enum Pipe { PIPE_A, PIPE_B, PIPE_C, PIPE_INVALID };
19 
20 static const Pipe kPipes[kPipeCount] = {
21     PIPE_A, PIPE_B, PIPE_C,
22 };
23 
24 static constexpr uint32_t kImagePlaneCount = 3;
25 static constexpr uint32_t kCursorPlane = 2;
26 
27 // PIPE_SRCSZ
28 class PipeSourceSize : public hwreg::RegisterBase<PipeSourceSize, uint32_t> {
29 public:
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
37 class PipeBottomColor : public hwreg::RegisterBase<PipeBottomColor, uint32_t> {
38 public:
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
50 class PlaneSurface : public hwreg::RegisterBase<PlaneSurface, uint32_t> {
51 public:
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
67 class PlaneSurfaceLive : public hwreg::RegisterBase<PlaneSurfaceLive, uint32_t> {
68 public:
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
78 class PlaneSurfaceStride : public hwreg::RegisterBase<PlaneSurfaceStride, uint32_t> {
79 public:
80     static constexpr uint32_t kBaseAddr = 0x70188;
81 
82     DEF_FIELD(9, 0, stride);
83 };
84 
85 // PLANE_SIZE
86 class PlaneSurfaceSize : public hwreg::RegisterBase<PlaneSurfaceSize, uint32_t> {
87 public:
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
95 class PlaneControl : public hwreg::RegisterBase<PlaneControl, uint32_t> {
96 public:
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
140 class PlaneBufCfg : public hwreg::RegisterBase<PlaneBufCfg, uint32_t> {
141 public:
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
150 class PlaneWm : public hwreg::RegisterBase<PlaneWm, uint32_t> {
151 public:
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
160 class PlaneKeyMask : public hwreg::RegisterBase<PlaneKeyMask, uint32_t> {
161 public:
162     static constexpr uint32_t kBaseAddr = 0x70198;
163 
164     DEF_BIT(31, plane_alpha_enable);
165 };
166 
167 // PLANE_KEYMAX
168 class PlaneKeyMax : public hwreg::RegisterBase<PlaneKeyMax, uint32_t> {
169 public:
170     static constexpr uint32_t kBaseAddr = 0x701a0;
171 
172     DEF_FIELD(31, 24, plane_alpha_value);
173 };
174 
175 // PLANE_OFFSET
176 class PlaneOffset : public hwreg::RegisterBase<PlaneOffset, uint32_t> {
177 public:
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
185 class PlanePosition : public hwreg::RegisterBase<PlanePosition, uint32_t> {
186 public:
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
194 class PipeScalerCtrl : public hwreg::RegisterBase<PipeScalerCtrl, uint32_t> {
195 public:
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
224 class PipeScalerWinPosition : public hwreg::RegisterBase<PipeScalerWinPosition, uint32_t> {
225 public:
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
233 class PipeScalerWinSize : public hwreg::RegisterBase<PipeScalerWinSize, uint32_t> {
234 public:
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
242 class PipeDeInterrupt : public hwreg::RegisterBase<PipeDeInterrupt, uint32_t> {
243 public:
244     DEF_BIT(1, vsync);
245 };
246 
247 // CUR_BASE
248 class CursorBase : public hwreg::RegisterBase<CursorBase, uint32_t> {
249 public:
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
259 class CursorCtrl : public hwreg::RegisterBase<CursorCtrl, uint32_t> {
260 public:
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
272 class CursorPos : public hwreg::RegisterBase<CursorPos, uint32_t> {
273 public:
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
283 class CursorSurfaceLive : public hwreg::RegisterBase<CursorSurfaceLive, uint32_t> {
284 public:
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
292 class CscCoeff : public hwreg::RegisterBase<CscCoeff, uint32_t> {
293 public:
294     static constexpr uint32_t kBaseAddr = 0x49010;
295 
coefficient(uint32_t i,uint32_t j)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 
303 class CscCoeffFormat : public hwreg::RegisterBase<CscCoeffFormat, uint16_t> {
304 public:
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
317 class CscMode : public hwreg::RegisterBase<CscMode, uint32_t> {
318 public:
319     static constexpr uint32_t kBaseAddr = 0x49028;
320 };
321 
322 // CSC_POSTOFF / CSC_PREOFF
323 class CscOffset : public hwreg::RegisterBase<CscOffset, uint32_t> {
324 public:
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.
333 class PipeRegs {
334 public:
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 
PipeRegs(Pipe pipe)340     PipeRegs(Pipe pipe) : pipe_(pipe) { }
341 
PipeSourceSize()342     hwreg::RegisterAddr<registers::PipeSourceSize> PipeSourceSize() {
343         return GetReg<registers::PipeSourceSize>();
344     }
PipeBottomColor()345     hwreg::RegisterAddr<registers::PipeBottomColor> PipeBottomColor() {
346         return GetReg<registers::PipeBottomColor>();
347     }
348 
PlaneSurface(int32_t plane_num)349     hwreg::RegisterAddr<registers::PlaneSurface> PlaneSurface(int32_t plane_num) {
350         return GetPlaneReg<registers::PlaneSurface>(plane_num);
351     }
PlaneSurfaceLive(int32_t plane_num)352     hwreg::RegisterAddr<registers::PlaneSurfaceLive> PlaneSurfaceLive(int32_t plane_num) {
353         return GetPlaneReg<registers::PlaneSurfaceLive>(plane_num);
354     }
PlaneSurfaceStride(int32_t plane_num)355     hwreg::RegisterAddr<registers::PlaneSurfaceStride> PlaneSurfaceStride(int32_t plane_num) {
356         return GetPlaneReg<registers::PlaneSurfaceStride>(plane_num);
357     }
PlaneSurfaceSize(int32_t plane_num)358     hwreg::RegisterAddr<registers::PlaneSurfaceSize> PlaneSurfaceSize(int32_t plane_num) {
359         return GetPlaneReg<registers::PlaneSurfaceSize>(plane_num);
360     }
PlaneControl(int32_t plane_num)361     hwreg::RegisterAddr<registers::PlaneControl> PlaneControl(int32_t plane_num) {
362         return GetPlaneReg<registers::PlaneControl>(plane_num);
363     }
PlaneOffset(int32_t plane_num)364     hwreg::RegisterAddr<registers::PlaneOffset> PlaneOffset(int32_t plane_num) {
365         return GetPlaneReg<registers::PlaneOffset>(plane_num);
366     }
PlanePosition(int32_t plane_num)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
PlaneBufCfg(int plane)371     hwreg::RegisterAddr<registers::PlaneBufCfg> PlaneBufCfg(int plane) {
372         return hwreg::RegisterAddr<registers::PlaneBufCfg>(
373                 PlaneBufCfg::kBaseAddr + 0x1000 * pipe_ + 0x100 * plane);
374     }
375 
PlaneWatermark(int plane,int wm_num)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 
PlaneKeyMask(int32_t plane_num)381     hwreg::RegisterAddr<registers::PlaneKeyMask> PlaneKeyMask(int32_t plane_num) {
382         return GetPlaneReg<registers::PlaneKeyMask>(plane_num);
383     }
PlaneKeyMax(int32_t plane_num)384     hwreg::RegisterAddr<registers::PlaneKeyMax> PlaneKeyMax(int32_t plane_num) {
385         return GetPlaneReg<registers::PlaneKeyMax>(plane_num);
386     }
387 
PipeScalerCtrl(int num)388     hwreg::RegisterAddr<registers::PipeScalerCtrl> PipeScalerCtrl(int num) {
389         return hwreg::RegisterAddr<registers::PipeScalerCtrl>(
390                 PipeScalerCtrl::kBaseAddr + 0x800 * pipe_ + num * 0x100);
391     }
392 
PipeScalerWinPosition(int num)393     hwreg::RegisterAddr<registers::PipeScalerWinPosition> PipeScalerWinPosition(int num) {
394         return hwreg::RegisterAddr<registers::PipeScalerWinPosition>(
395                 PipeScalerWinPosition::kBaseAddr + 0x800 * pipe_ + num * 0x100);
396     }
397 
PipeScalerWinSize(int num)398     hwreg::RegisterAddr<registers::PipeScalerWinSize> PipeScalerWinSize(int num) {
399         return hwreg::RegisterAddr<registers::PipeScalerWinSize>(
400                 PipeScalerWinSize::kBaseAddr + 0x800 * pipe_ + num * 0x100);
401     }
402 
PipeDeInterrupt(uint32_t type)403     hwreg::RegisterAddr<registers::PipeDeInterrupt> PipeDeInterrupt(uint32_t type) {
404         return hwreg::RegisterAddr<registers::PipeDeInterrupt>(type + 0x10 * pipe_);
405     }
406 
CursorBase()407     hwreg::RegisterAddr<registers::CursorBase> CursorBase() {
408         return GetReg<registers::CursorBase>();
409     }
410 
CursorCtrl()411     hwreg::RegisterAddr<registers::CursorCtrl> CursorCtrl() {
412         return GetReg<registers::CursorCtrl>();
413     }
414 
CursorPos()415     hwreg::RegisterAddr<registers::CursorPos> CursorPos() {
416         return GetReg<registers::CursorPos>();
417     }
418 
CursorSurfaceLive()419     hwreg::RegisterAddr<registers::CursorSurfaceLive> CursorSurfaceLive() {
420         return GetReg<registers::CursorSurfaceLive>();
421     }
422 
CscCoeff(uint32_t i,uint32_t j)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 
CscMode()429     hwreg::RegisterAddr<registers::CscMode> CscMode() {
430         return GetCscReg<registers::CscMode>(registers::CscMode::kBaseAddr);
431     }
432 
CscOffset(bool preoffset,uint32_t component_idx)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 
439 private:
GetReg()440     template <class RegType> hwreg::RegisterAddr<RegType> GetReg() {
441         return hwreg::RegisterAddr<RegType>(RegType::kBaseAddr + 0x1000 * pipe_);
442     }
443 
GetPlaneReg(int32_t plane)444     template <class RegType> hwreg::RegisterAddr<RegType> GetPlaneReg(int32_t plane) {
445         return hwreg::RegisterAddr<RegType>(RegType::kBaseAddr + 0x1000 * pipe_ + 0x100 * plane);
446     }
447 
GetCscReg(uint32_t base)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
456 typedef 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