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