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 <assert.h>
6#include <ddk/binding.h>
7#include <ddk/debug.h>
8#include <ddk/device.h>
9#include <ddk/driver.h>
10#include <ddk/io-buffer.h>
11#include <ddk/protocol/platform-defs.h>
12#include <ddk/protocol/platform-device.h>
13#include <stdint.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <unistd.h>
18
19#include "hdmitx.h"
20#include "registers.h"
21#include "vim-display.h"
22#include <hw/reg.h>
23#include <zircon/assert.h>
24#include <zircon/syscalls.h>
25
26void osd_debug_dump_register_all(vim2_display_t* display) {
27    uint32_t reg = 0;
28    uint32_t offset = 0;
29    uint32_t index = 0;
30
31    reg = VPU_VPU_VIU_VENC_MUX_CTRL;
32    DISP_INFO("reg[0x%x]: 0x%08x\n", (reg >> 2), READ32_VPU_REG(reg));
33    reg = VPU_VPP_MISC;
34    DISP_INFO("reg[0x%x]: 0x%08x\n", (reg >> 2), READ32_VPU_REG(reg));
35    reg = VPU_VPP_OFIFO_SIZE;
36    DISP_INFO("reg[0x%x]: 0x%08x\n", (reg >> 2), READ32_VPU_REG(reg));
37    reg = VPU_VPP_HOLD_LINES;
38    DISP_INFO("reg[0x%x]: 0x%08x\n", (reg >> 2), READ32_VPU_REG(reg));
39    reg = VPU_VPP_OSD_SC_CTRL0;
40    DISP_INFO("reg[0x%x]: 0x%08x\n", (reg >> 2), READ32_VPU_REG(reg));
41    reg = VPU_VPP_OSD_SCI_WH_M1;
42    DISP_INFO("reg[0x%x]: 0x%08x\n", (reg >> 2), READ32_VPU_REG(reg));
43    reg = VPU_VPP_OSD_SCO_H_START_END;
44    DISP_INFO("reg[0x%x]: 0x%08x\n", (reg >> 2), READ32_VPU_REG(reg));
45    reg = VPU_VPP_OSD_SCO_V_START_END;
46    DISP_INFO("reg[0x%x]: 0x%08x\n\n", (reg >> 2), READ32_VPU_REG(reg));
47    reg = VPU_VPP_POSTBLEND_H_SIZE;
48    DISP_INFO("reg[0x%x]: 0x%08x\n\n", (reg >> 2), READ32_VPU_REG(reg));
49
50    for (index = 0; index < 2; index++) {
51        if (index == 1)
52            offset = (0x20 << 2);
53        reg = offset + VPU_VIU_OSD1_FIFO_CTRL_STAT;
54        DISP_INFO("reg[0x%x]: 0x%08x\n", (reg >> 2), READ32_VPU_REG(reg));
55        reg = offset + VPU_VIU_OSD1_CTRL_STAT;
56        DISP_INFO("reg[0x%x]: 0x%08x\n", (reg >> 2), READ32_VPU_REG(reg));
57        reg = offset + VPU_VIU_OSD1_BLK0_CFG_W0;
58        DISP_INFO("reg[0x%x]: 0x%08x\n", (reg >> 2), READ32_VPU_REG(reg));
59        reg = offset + VPU_VIU_OSD1_BLK0_CFG_W1;
60        DISP_INFO("reg[0x%x]: 0x%08x\n", (reg >> 2), READ32_VPU_REG(reg));
61        reg = offset + VPU_VIU_OSD1_BLK0_CFG_W2;
62        DISP_INFO("reg[0x%x]: 0x%08x\n", (reg >> 2), READ32_VPU_REG(reg));
63        reg = offset + VPU_VIU_OSD1_BLK0_CFG_W3;
64        DISP_INFO("reg[0x%x]: 0x%08x\n", (reg >> 2), READ32_VPU_REG(reg));
65        reg = VPU_VIU_OSD1_BLK0_CFG_W4;
66        if (index == 1)
67            reg = VPU_VIU_OSD2_BLK0_CFG_W4;
68        DISP_INFO("reg[0x%x]: 0x%08x\n\n", (reg >> 2), READ32_VPU_REG(reg));
69    }
70}
71
72void disable_vd(vim2_display* display, uint32_t vd_index) {
73    display->vd1_image_valid = false;
74    hwreg::RegisterIo vpu(io_buffer_virt(&display->mmio_vpu));
75    registers::Vd(vd_index).IfGenReg().ReadFrom(&vpu).set_enable(false).WriteTo(&vpu);
76    registers::VpuVppMisc::Get()
77        .ReadFrom(&vpu)
78        .set_vd1_enable_postblend(false)
79        .WriteTo(&vpu);
80}
81
82void configure_vd(vim2_display* display, uint32_t vd_index) {
83    disable_vd(display, vd_index);
84    hwreg::RegisterIo vpu(io_buffer_virt(&display->mmio_vpu));
85    uint32_t x_start, x_end, y_start, y_end;
86    x_start = y_start = 0;
87    x_end = display->cur_display_mode.h_addressable - 1;
88    y_end = display->cur_display_mode.v_addressable - 1;
89
90    auto vd = registers::Vd(vd_index);
91    vd.IfLumaX0().FromValue(0).set_end(x_end).set_start(x_start).WriteTo(&vpu);
92    vd.IfLumaY0().FromValue(0).set_end(y_end).set_start(y_start).WriteTo(&vpu);
93    vd.IfChromaX0().FromValue(0).set_end(x_end / 2).set_start(x_start / 2).WriteTo(&vpu);
94    vd.IfChromaY0().FromValue(0).set_end(y_end / 2).set_start(y_start / 2).WriteTo(&vpu);
95    vd.IfGenReg2().FromValue(0).set_color_map(1).WriteTo(&vpu);
96    vd.FmtCtrl()
97        .FromValue(0)
98        .set_vertical_enable(true)
99        .set_vertical_phase_step(8)
100        .set_vertical_initial_phase(0xc)
101        .set_vertical_repeat_line0(true)
102        .set_horizontal_enable(true)
103        .set_horizontal_yc_ratio(1)
104        .WriteTo(&vpu);
105    vd.FmtW()
106        .FromValue(0)
107        .set_horizontal_width(display->cur_display_mode.h_addressable)
108        .set_vertical_width(display->cur_display_mode.h_addressable / 2)
109        .WriteTo(&vpu);
110
111    vd.IfRptLoop().FromValue(0).WriteTo(&vpu);
112    vd.IfLuma0RptPat().FromValue(0).WriteTo(&vpu);
113    vd.IfChroma0RptPat().FromValue(0).WriteTo(&vpu);
114    vd.IfLumaPsel().FromValue(0).WriteTo(&vpu);
115    vd.IfChromaPsel().FromValue(0).WriteTo(&vpu);
116}
117
118void flip_vd(vim2_display* display, uint32_t vd_index, uint32_t index) {
119    display->vd1_image_valid = true;
120    display->vd1_image = index;
121    hwreg::RegisterIo vpu(io_buffer_virt(&display->mmio_vpu));
122    auto vd = registers::Vd(vd_index);
123    vd.IfGenReg()
124        .FromValue(0)
125        .set_enable(true)
126        .set_separate_en(true)
127        .set_chro_rpt_lastl_ctrl(true)
128        .set_hold_lines(3)
129        .set_urgent_luma(true)
130        .set_urgent_chroma(true)
131        .WriteTo(&vpu);
132    vd.IfCanvas0().FromValue(index).WriteTo(&vpu);
133    registers::VpuVppMisc::Get()
134        .ReadFrom(&vpu)
135        .set_vd1_enable_postblend(true)
136        .WriteTo(&vpu);
137}
138
139void disable_osd(vim2_display_t* display, uint32_t osd_index) {
140    display->current_image_valid = false;
141    hwreg::RegisterIo vpu(io_buffer_virt(&display->mmio_vpu));
142    auto osd = registers::Osd(osd_index);
143    osd
144        .CtrlStat()
145        .ReadFrom(&vpu)
146        .set_osd_blk_enable(false)
147        .WriteTo(&vpu);
148    if (osd_index == 0) {
149        registers::VpuVppMisc::Get()
150            .ReadFrom(&vpu)
151            .set_osd2_enable_postblend(false)
152            .WriteTo(&vpu);
153    } else {
154        registers::VpuVppMisc::Get()
155            .ReadFrom(&vpu)
156            .set_osd1_enable_postblend(false)
157            .WriteTo(&vpu);
158    }
159}
160
161// Disables the OSD until a flip happens
162zx_status_t configure_osd(vim2_display_t* display, uint32_t osd_index) {
163    uint32_t x_start, x_end, y_start, y_end;
164    x_start = y_start = 0;
165    x_end = display->cur_display_mode.h_addressable - 1;
166    y_end = display->cur_display_mode.v_addressable - 1;
167
168    disable_osd(display, osd_index);
169    hwreg::RegisterIo vpu(io_buffer_virt(&display->mmio_vpu));
170    auto osd = registers::Osd(osd_index);
171    registers::VpuVppOsdScCtrl0::Get().FromValue(0).WriteTo(&vpu);
172
173    osd.CtrlStat2()
174        .ReadFrom(&vpu)
175        .set_replaced_alpha_en(true)
176        .set_replaced_alpha(0xff)
177        .WriteTo(&vpu);
178
179    osd.Blk0CfgW1()
180        .FromValue(0)
181        .set_virtual_canvas_x_end(x_end)
182        .set_virtual_canvas_x_start(x_start)
183        .WriteTo(&vpu);
184    osd.Blk0CfgW2()
185        .FromValue(0)
186        .set_virtual_canvas_y_end(y_end)
187        .set_virtual_canvas_y_start(y_start)
188        .WriteTo(&vpu);
189    osd.Blk0CfgW3().FromValue(0).set_display_h_end(x_end).set_display_h_start(x_start).WriteTo(
190        &vpu);
191    osd.Blk0CfgW4().FromValue(0).set_display_v_end(y_end).set_display_v_start(y_start).WriteTo(
192        &vpu);
193
194    registers::VpuVppOsdScoHStartEnd::Get().FromValue(0).WriteTo(&vpu);
195    registers::VpuVppOsdScoVStartEnd::Get().FromValue(0).WriteTo(&vpu);
196
197    registers::VpuVppPostblendHSize::Get()
198        .FromValue(display->cur_display_mode.h_addressable)
199        .WriteTo(&vpu);
200    registers::VpuVppOsdSciWhM1::Get().FromValue(0).WriteTo(&vpu);
201
202    return ZX_OK;
203}
204
205void flip_osd(vim2_display_t* display, uint32_t osd_index, uint8_t idx) {
206    display->current_image = idx;
207    display->current_image_valid = true;
208    hwreg::RegisterIo vpu(io_buffer_virt(&display->mmio_vpu));
209    auto osd = registers::Osd(osd_index);
210    osd.Blk0CfgW0()
211        .FromValue(0)
212        .set_tbl_addr(idx)
213        .set_little_endian(true)
214        .set_block_mode(registers::VpuViuOsdBlk0CfgW0::kBlockMode32Bit)
215        .set_rgb_en(true)
216        .set_color_matrix(registers::VpuViuOsdBlk0CfgW0::kColorMatrixARGB8888)
217        .WriteTo(&vpu);
218    osd.CtrlStat()
219        .ReadFrom(&vpu)
220        .set_osd_blk_enable(true)
221        .WriteTo(&vpu);
222    if (osd_index == 0) {
223        registers::VpuVppMisc::Get()
224            .ReadFrom(&vpu)
225            .set_osd1_enable_postblend(true)
226            .WriteTo(&vpu);
227    } else {
228        registers::VpuVppMisc::Get()
229            .ReadFrom(&vpu)
230            .set_osd2_enable_postblend(true)
231            .WriteTo(&vpu);
232    }
233}
234