1 // Copyright 2018 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 #include "vpu.h"
6 #include "vpu-regs.h"
7 #include "hhi-regs.h"
8 #include "vpp-regs.h"
9 #include <ddk/debug.h>
10 #include <ddktl/device.h>
11
12 namespace astro_display {
13
14 namespace {
15 constexpr uint32_t kVpuMux = 0;
16 constexpr uint32_t kVpuDiv = 3;
17
18 constexpr int16_t RGB709_to_YUV709l_coeff[24] = {
19 0x0000, 0x0000, 0x0000,
20 0x00bb, 0x0275, 0x003f,
21 0x1f99, 0x1ea6, 0x01c2,
22 0x01c2, 0x1e67, 0x1fd7,
23 0x0000, 0x0000, 0x0000,
24 0x0000, 0x0000, 0x0000,
25 0x0040, 0x0200, 0x0200,
26 0x0000, 0x0000, 0x0000,
27 };
28
29 constexpr int16_t YUV709l_to_RGB709_coeff12[24] = {
30 -256, -2048, -2048,
31 4788, 0, 7372,
32 4788, -876, -2190,
33 4788, 8686, 0,
34 0, 0, 0,
35 0, 0, 0,
36 0, 0, 0,
37 0, 0, 0,
38 };
39 } // namespace
40
41 // AOBUS Register
42 #define AOBUS_GEN_PWR_SLEEP0 (0x03a << 2)
43
44 // CBUS Reset Register
45 #define RESET0_LEVEL (0x0420 << 2)
46 #define RESET1_LEVEL (0x0421 << 2)
47 #define RESET2_LEVEL (0x0422 << 2)
48 #define RESET4_LEVEL (0x0424 << 2)
49 #define RESET7_LEVEL (0x0427 << 2)
50
51 #define READ32_VPU_REG(a) vpu_mmio_->Read32(a)
52 #define WRITE32_VPU_REG(a, v) vpu_mmio_->Write32(v, a)
53
54 #define READ32_HHI_REG(a) hhi_mmio_->Read32(a)
55 #define WRITE32_HHI_REG(a, v) hhi_mmio_->Write32(v, a)
56
57 #define READ32_AOBUS_REG(a) aobus_mmio_->Read32(a)
58 #define WRITE32_AOBUS_REG(a, v) aobus_mmio_->Write32(v, a)
59
60 #define READ32_CBUS_REG(a) cbus_mmio_->Read32(a)
61 #define WRITE32_CBUS_REG(a, v) cbus_mmio_->Write32(v, a)
62
Init(zx_device_t * parent)63 zx_status_t Vpu::Init(zx_device_t* parent) {
64 if (initialized_) {
65 return ZX_OK;
66 }
67 zx_status_t status = device_get_protocol(parent, ZX_PROTOCOL_PDEV, &pdev_);
68 if (status != ZX_OK) {
69 return status;
70 }
71
72 // Map VPU registers
73 mmio_buffer_t mmio;
74 status = pdev_map_mmio_buffer2(&pdev_, MMIO_VPU, ZX_CACHE_POLICY_UNCACHED_DEVICE,
75 &mmio);
76 if (status != ZX_OK) {
77 DISP_ERROR("vpu: Could not map VPU mmio\n");
78 return status;
79 }
80 vpu_mmio_ = ddk::MmioBuffer(mmio);
81
82 // Map HHI registers
83 status = pdev_map_mmio_buffer2(&pdev_, MMIO_HHI, ZX_CACHE_POLICY_UNCACHED_DEVICE,
84 &mmio);
85 if (status != ZX_OK) {
86 DISP_ERROR("vpu: Could not map HHI mmio\n");
87 return status;
88 }
89 hhi_mmio_ = ddk::MmioBuffer(mmio);
90
91 // Map AOBUS registers
92 status = pdev_map_mmio_buffer2(&pdev_, MMIO_AOBUS, ZX_CACHE_POLICY_UNCACHED_DEVICE,
93 &mmio);
94 if (status != ZX_OK) {
95 DISP_ERROR("vpu: Could not map AOBUS mmio\n");
96 return status;
97 }
98 aobus_mmio_ = ddk::MmioBuffer(mmio);
99
100 // Map CBUS registers
101 status = pdev_map_mmio_buffer2(&pdev_, MMIO_CBUS, ZX_CACHE_POLICY_UNCACHED_DEVICE,
102 &mmio);
103 if (status != ZX_OK) {
104 DISP_ERROR("vpu: Could not map CBUS mmio\n");
105 return status;
106 }
107 cbus_mmio_ = ddk::MmioBuffer(mmio);
108
109 // VPU object is ready to be used
110 initialized_ = true;
111 return ZX_OK;
112 }
113
VppInit()114 void Vpu::VppInit() {
115 ZX_DEBUG_ASSERT(initialized_);
116
117 // init vpu fifo control register
118 SET_BIT32(VPU, VPP_OFIFO_SIZE, 0xFFF, 0, 12);
119 WRITE32_REG(VPU, VPP_HOLD_LINES, 0x08080808);
120 // default probe_sel, for highlight en
121 SET_BIT32(VPU, VPP_MATRIX_CTRL, 0x7, 12, 3);
122
123 // setting up os1 for rgb -> yuv limit
124 const int16_t* m = RGB709_to_YUV709l_coeff;
125
126 // VPP WRAP OSD1 matrix
127 WRITE32_REG(VPU, VPP_WRAP_OSD1_MATRIX_PRE_OFFSET0_1,
128 ((m[0] & 0xfff) << 16) | (m[1] & 0xfff));
129 WRITE32_REG(VPU, VPP_WRAP_OSD1_MATRIX_PRE_OFFSET2,
130 m[2] & 0xfff);
131 WRITE32_REG(VPU, VPP_WRAP_OSD1_MATRIX_COEF00_01,
132 ((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff));
133 WRITE32_REG(VPU, VPP_WRAP_OSD1_MATRIX_COEF02_10,
134 ((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff));
135 WRITE32_REG(VPU, VPP_WRAP_OSD1_MATRIX_COEF11_12,
136 ((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff));
137 WRITE32_REG(VPU, VPP_WRAP_OSD1_MATRIX_COEF20_21,
138 ((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff));
139 WRITE32_REG(VPU, VPP_WRAP_OSD1_MATRIX_COEF22,
140 m[11] & 0x1fff);
141 WRITE32_REG(VPU, VPP_WRAP_OSD1_MATRIX_OFFSET0_1,
142 ((m[18] & 0xfff) << 16) | (m[19] & 0xfff));
143 WRITE32_REG(VPU, VPP_WRAP_OSD1_MATRIX_OFFSET2,
144 m[20] & 0xfff);
145 SET_BIT32(VPU, VPP_WRAP_OSD1_MATRIX_EN_CTRL, 1, 0, 1);
146
147 // VPP WRAP OSD2 matrix
148 WRITE32_REG(VPU, VPP_WRAP_OSD2_MATRIX_PRE_OFFSET0_1,
149 ((m[0] & 0xfff) << 16) | (m[1] & 0xfff));
150 WRITE32_REG(VPU, VPP_WRAP_OSD2_MATRIX_PRE_OFFSET2,
151 m[2] & 0xfff);
152 WRITE32_REG(VPU, VPP_WRAP_OSD2_MATRIX_COEF00_01,
153 ((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff));
154 WRITE32_REG(VPU, VPP_WRAP_OSD2_MATRIX_COEF02_10,
155 ((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff));
156 WRITE32_REG(VPU, VPP_WRAP_OSD2_MATRIX_COEF11_12,
157 ((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff));
158 WRITE32_REG(VPU, VPP_WRAP_OSD2_MATRIX_COEF20_21,
159 ((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff));
160 WRITE32_REG(VPU, VPP_WRAP_OSD2_MATRIX_COEF22,
161 m[11] & 0x1fff);
162 WRITE32_REG(VPU, VPP_WRAP_OSD2_MATRIX_OFFSET0_1,
163 ((m[18] & 0xfff) << 16) | (m[19] & 0xfff));
164 WRITE32_REG(VPU, VPP_WRAP_OSD2_MATRIX_OFFSET2,
165 m[20] & 0xfff);
166 SET_BIT32(VPU, VPP_WRAP_OSD2_MATRIX_EN_CTRL, 1, 0, 1);
167
168 // VPP WRAP OSD3 matrix
169 WRITE32_REG(VPU, VPP_WRAP_OSD3_MATRIX_PRE_OFFSET0_1,
170 ((m[0] & 0xfff) << 16) | (m[1] & 0xfff));
171 WRITE32_REG(VPU, VPP_WRAP_OSD3_MATRIX_PRE_OFFSET2,
172 m[2] & 0xfff);
173 WRITE32_REG(VPU, VPP_WRAP_OSD3_MATRIX_COEF00_01,
174 ((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff));
175 WRITE32_REG(VPU, VPP_WRAP_OSD3_MATRIX_COEF02_10,
176 ((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff));
177 WRITE32_REG(VPU, VPP_WRAP_OSD3_MATRIX_COEF11_12,
178 ((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff));
179 WRITE32_REG(VPU, VPP_WRAP_OSD3_MATRIX_COEF20_21,
180 ((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff));
181 WRITE32_REG(VPU, VPP_WRAP_OSD3_MATRIX_COEF22,
182 m[11] & 0x1fff);
183 WRITE32_REG(VPU, VPP_WRAP_OSD3_MATRIX_OFFSET0_1,
184 ((m[18] & 0xfff) << 16) | (m[19] & 0xfff));
185 WRITE32_REG(VPU, VPP_WRAP_OSD3_MATRIX_OFFSET2,
186 m[20] & 0xfff);
187 SET_BIT32(VPU, VPP_WRAP_OSD3_MATRIX_EN_CTRL, 1, 0, 1);
188
189 WRITE32_REG(VPU, DOLBY_PATH_CTRL, 0xf);
190
191 // POST2 matrix: YUV limit -> RGB default is 12bit
192 m = YUV709l_to_RGB709_coeff12;
193
194 // VPP WRAP POST2 matrix
195 WRITE32_REG(VPU, VPP_POST2_MATRIX_PRE_OFFSET0_1,
196 (((m[0] >> 2) & 0xfff) << 16) | ((m[1] >> 2) & 0xfff));
197 WRITE32_REG(VPU, VPP_POST2_MATRIX_PRE_OFFSET2,
198 (m[2] >> 2) & 0xfff);
199 WRITE32_REG(VPU, VPP_POST2_MATRIX_COEF00_01,
200 (((m[3] >> 2) & 0x1fff) << 16) | ((m[4] >> 2) & 0x1fff));
201 WRITE32_REG(VPU, VPP_POST2_MATRIX_COEF02_10,
202 (((m[5] >> 2) & 0x1fff) << 16) | ((m[6] >> 2) & 0x1fff));
203 WRITE32_REG(VPU, VPP_POST2_MATRIX_COEF11_12,
204 (((m[7] >> 2) & 0x1fff) << 16) | ((m[8] >> 2) & 0x1fff));
205 WRITE32_REG(VPU, VPP_POST2_MATRIX_COEF20_21,
206 (((m[9] >> 2) & 0x1fff) << 16) | ((m[10] >> 2) & 0x1fff));
207 WRITE32_REG(VPU, VPP_POST2_MATRIX_COEF22,
208 (m[11] >> 2) & 0x1fff);
209 WRITE32_REG(VPU, VPP_POST2_MATRIX_OFFSET0_1,
210 (((m[18] >> 2) & 0xfff) << 16) | ((m[19] >> 2) & 0xfff));
211 WRITE32_REG(VPU, VPP_POST2_MATRIX_OFFSET2,
212 (m[20] >> 2) & 0xfff);
213 SET_BIT32(VPU, VPP_POST2_MATRIX_EN_CTRL, 1, 0, 1);
214
215
216 SET_BIT32(VPU, VPP_MATRIX_CTRL, 1, 0, 1);
217 SET_BIT32(VPU, VPP_MATRIX_CTRL, 0, 8, 3);
218
219 // 709L to RGB
220 WRITE32_REG(VPU, VPP_MATRIX_PRE_OFFSET0_1, 0x0FC00E00);
221 WRITE32_REG(VPU, VPP_MATRIX_PRE_OFFSET2, 0x00000E00);
222 // ycbcr limit range, 709 to RGB
223 // -16 1.164 0 1.793 0
224 // -128 1.164 -0.213 -0.534 0
225 // -128 1.164 2.115 0 0
226 WRITE32_REG(VPU, VPP_MATRIX_COEF00_01, 0x04A80000);
227 WRITE32_REG(VPU, VPP_MATRIX_COEF02_10, 0x072C04A8);
228 WRITE32_REG(VPU, VPP_MATRIX_COEF11_12, 0x1F261DDD);
229 WRITE32_REG(VPU, VPP_MATRIX_COEF20_21, 0x04A80876);
230 WRITE32_REG(VPU, VPP_MATRIX_COEF22, 0x0);
231 WRITE32_REG(VPU, VPP_MATRIX_OFFSET0_1, 0x0);
232 WRITE32_REG(VPU, VPP_MATRIX_OFFSET2, 0x0);
233
234 SET_BIT32(VPU, VPP_MATRIX_CLIP, 0, 5, 3);
235 }
236
ConfigureClock()237 void Vpu::ConfigureClock() {
238 ZX_DEBUG_ASSERT(initialized_);
239 // vpu clock
240 WRITE32_REG(HHI, HHI_VPU_CLK_CNTL, ((kVpuMux << 9) | (kVpuDiv << 0)));
241 SET_BIT32(HHI, HHI_VPU_CLK_CNTL, 1, 8, 1);
242
243 // vpu clkb
244 // bit 0 is set since kVpuClkFrequency > clkB max frequency (350MHz)
245 WRITE32_REG(HHI, HHI_VPU_CLKB_CNTL, ((1 << 8) | (1 << 0)));
246
247 // vapb clk
248 // turn on ge2d clock since kVpuClkFrequency > 250MHz
249 WRITE32_REG(HHI, HHI_VAPBCLK_CNTL, (1 << 30) | (0 << 9) | (1 << 0));
250
251 SET_BIT32(HHI, HHI_VAPBCLK_CNTL, 1, 8, 1);
252
253 SET_BIT32(HHI, HHI_VID_CLK_CNTL2, 0, 0, 8);
254
255 // dmc_arb_config
256 WRITE32_REG(VPU, VPU_RDARB_MODE_L1C1, 0x0);
257 WRITE32_REG(VPU, VPU_RDARB_MODE_L1C2, 0x10000);
258 WRITE32_REG(VPU, VPU_RDARB_MODE_L2C1, 0x900000);
259 WRITE32_REG(VPU, VPU_WRARB_MODE_L2C1, 0x20000);
260 }
261
PowerOn()262 void Vpu::PowerOn() {
263 ZX_DEBUG_ASSERT(initialized_);
264 SET_BIT32(AOBUS, AOBUS_GEN_PWR_SLEEP0, 0, 8, 1); // [8] power on
265
266 // power up memories
267 for (int i = 0; i < 32; i+=2) {
268 SET_BIT32(HHI, HHI_VPU_MEM_PD_REG0, 0, i, 2);
269 zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
270 }
271 for (int i = 0; i < 32; i+=2) {
272 SET_BIT32(HHI, HHI_VPU_MEM_PD_REG1, 0, i, 2);
273 zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
274 }
275 SET_BIT32(HHI, HHI_VPU_MEM_PD_REG2, 0, 0, 2);
276 zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
277 for (int i = 4; i < 18; i+=2) {
278 SET_BIT32(HHI, HHI_VPU_MEM_PD_REG2, 0, i, 2);
279 zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
280 }
281 SET_BIT32(HHI, HHI_VPU_MEM_PD_REG2, 0, 30, 2);
282 zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
283
284 for (int i = 8; i < 16; i++) {
285 SET_BIT32(HHI, HHI_MEM_PD_REG0, 0, i, 1);
286 zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
287 }
288 zx_nanosleep(zx_deadline_after(ZX_USEC(20)));
289
290 // Reset VIU + VENC
291 // Reset VENCI + VENCP + VADC + VENCL
292 // Reset HDMI-APB + HDMI-SYS + HDMI-TX + HDMI-CEC
293 CLEAR_MASK32(CBUS, RESET0_LEVEL, ((1<<5) | (1<<10) | (1<<19) | (1<<13)));
294 CLEAR_MASK32(CBUS, RESET1_LEVEL, (1<<5));
295 CLEAR_MASK32(CBUS, RESET2_LEVEL, (1<<15));
296 CLEAR_MASK32(CBUS, RESET4_LEVEL,
297 ((1<<6) | (1<<7) | (1<<13) | (1<<5) | (1<<9) | (1<<4) | (1<<12)));
298 CLEAR_MASK32(CBUS, RESET7_LEVEL, (1<<7));
299
300 // Remove VPU_HDMI ISO
301 SET_BIT32(AOBUS, AOBUS_GEN_PWR_SLEEP0, 0, 9, 1); // [9] VPU_HDMI
302
303 // release Reset
304 SET_MASK32(CBUS, RESET0_LEVEL, ((1 << 5) | (1<<10) | (1<<19) | (1<<13)));
305 SET_MASK32(CBUS, RESET1_LEVEL, (1<<5));
306 SET_MASK32(CBUS, RESET2_LEVEL, (1<<15));
307 SET_MASK32(CBUS, RESET4_LEVEL,
308 ((1<<6) | (1<<7) | (1<<13) | (1<<5) | (1<<9) | (1<<4) | (1<<12)));
309 SET_MASK32(CBUS, RESET7_LEVEL, (1<<7));
310
311 ConfigureClock();
312 }
313
PowerOff()314 void Vpu::PowerOff() {
315 ZX_DEBUG_ASSERT(initialized_);
316 // Power down VPU_HDMI
317 // Enable Isolation
318 SET_BIT32(AOBUS, AOBUS_GEN_PWR_SLEEP0, 1, 9, 1); // ISO
319 zx_nanosleep(zx_deadline_after(ZX_USEC(20)));
320
321 // power down memories
322 for (int i = 0; i < 32; i+=2) {
323 SET_BIT32(HHI, HHI_VPU_MEM_PD_REG0, 0x3, i, 2);
324 zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
325 }
326 for (int i = 0; i < 32; i+=2) {
327 SET_BIT32(HHI, HHI_VPU_MEM_PD_REG1, 0x3, i, 2);
328 zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
329 }
330 SET_BIT32(HHI, HHI_VPU_MEM_PD_REG2, 0x3, 0, 2);
331 zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
332 for (int i = 4; i < 18; i+=2) {
333 SET_BIT32(HHI, HHI_VPU_MEM_PD_REG2, 0x3, i, 2);
334 zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
335 }
336 SET_BIT32(HHI, HHI_VPU_MEM_PD_REG2, 0x3, 30, 2);
337 zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
338
339 for (int i = 8; i < 16; i++) {
340 SET_BIT32(HHI, HHI_MEM_PD_REG0, 0x1, i, 1);
341 zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
342 }
343 zx_nanosleep(zx_deadline_after(ZX_USEC(20)));
344
345 // Power down VPU domain
346 SET_BIT32(AOBUS, AOBUS_GEN_PWR_SLEEP0, 1, 8, 1); // PDN
347
348 SET_BIT32(HHI, HHI_VAPBCLK_CNTL, 0, 8, 1);
349 SET_BIT32(HHI, HHI_VPU_CLK_CNTL, 0, 8, 1);
350 }
351 } // namespace astro_display
352