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 "osd.h"
6 #include "vpp-regs.h"
7 #include "vpu-regs.h"
8 #include "rdma-regs.h"
9 #include <ddk/debug.h>
10 #include <ddktl/device.h>
11 
12 namespace astro_display {
13 
14 #define READ32_VPU_REG(a)               vpu_mmio_->Read32(a)
15 #define WRITE32_VPU_REG(a, v)           vpu_mmio_->Write32(v, a)
16 
17 namespace {
18 constexpr uint32_t VpuViuOsd1BlkCfgTblAddrShift = 16;
19 constexpr uint32_t VpuViuOsd1BlkCfgLittleEndian = (1 << 15);
20 constexpr uint32_t VpuViuOsd1BlkCfgOsdBlkMode32Bit = 5;
21 constexpr uint32_t VpuViuOsd1BlkCfgOsdBlkModeShift = 8;
22 constexpr uint32_t VpuViuOsd1BlkCfgColorMatrixArgb = 1;
23 constexpr uint32_t VpuViuOsd1BlkCfgColorMatrixShift = 2;
24 constexpr uint32_t VpuViuOsd1CtrlStat2ReplacedAlphaEn = (1 << 14);
25 constexpr uint32_t VpuViuOsd1CtrlStat2ReplacedAlphaShift = 6u;
26 
27 constexpr uint32_t kOsdGlobalAlphaDef = 0xff;
28 constexpr uint32_t kHwOsdBlockEnable0 = 0x0001; // osd blk0 enable
29 
30 // We use bicubic interpolation for scaling.
31 // TODO(payamm): Add support for other types of interpolation
32 unsigned int osd_filter_coefs_bicubic[] = {
33     0x00800000, 0x007f0100, 0xff7f0200, 0xfe7f0300, 0xfd7e0500, 0xfc7e0600,
34     0xfb7d0800, 0xfb7c0900, 0xfa7b0b00, 0xfa7a0dff, 0xf9790fff, 0xf97711ff,
35     0xf87613ff, 0xf87416fe, 0xf87218fe, 0xf8701afe, 0xf76f1dfd, 0xf76d1ffd,
36     0xf76b21fd, 0xf76824fd, 0xf76627fc, 0xf76429fc, 0xf7612cfc, 0xf75f2ffb,
37     0xf75d31fb, 0xf75a34fb, 0xf75837fa, 0xf7553afa, 0xf8523cfa, 0xf8503ff9,
38     0xf84d42f9, 0xf84a45f9, 0xf84848f8
39 };
40 
41 } // namespace
42 
RdmaThread()43 int Osd::RdmaThread() {
44     zx_status_t status;
45     while (1) {
46         status = rdma_irq_.wait(nullptr);
47         if (status != ZX_OK) {
48             DISP_ERROR("RDMA Interrupt wait failed\n");
49             break;
50         }
51         // RDMA completed. Remove source for all finished DMA channels
52         for (int i = 0; i < kMaxRdmaChannels; i++) {
53             if (vpu_mmio_->Read32(VPU_RDMA_STATUS) & RDMA_STATUS_DONE(i)) {
54                 uint32_t regVal = vpu_mmio_->Read32(VPU_RDMA_ACCESS_AUTO);
55                 regVal &= ~RDMA_ACCESS_AUTO_INT_EN(i); // VSYNC interrupt source
56                 vpu_mmio_->Write32(regVal, VPU_RDMA_ACCESS_AUTO);
57             }
58         }
59     }
60     return status;
61 }
62 
Init(zx_device_t * parent)63 zx_status_t Osd::Init(zx_device_t* parent) {
64     if (initialized_) {
65         return ZX_OK;
66     }
67 
68     zx_status_t status = device_get_protocol(parent, ZX_PROTOCOL_PDEV, &pdev_);
69     if (status != ZX_OK) {
70         return status;
71     }
72 
73     // Map vpu mmio used by the OSD object
74     mmio_buffer_t mmio;
75     status = pdev_map_mmio_buffer2(&pdev_, MMIO_VPU, ZX_CACHE_POLICY_UNCACHED_DEVICE,
76                                   &mmio);
77     if (status != ZX_OK) {
78         DISP_ERROR("osd: Could not map VPU mmio\n");
79         return status;
80     }
81 
82     vpu_mmio_ = ddk::MmioBuffer(mmio);
83 
84     // Get BTI from parent
85     status = pdev_get_bti(&pdev_, 0, bti_.reset_and_get_address());
86     if (status != ZX_OK) {
87         DISP_ERROR("Could not get BTI handle\n");
88         return status;
89     }
90 
91     //Map RDMA Done Interrupt
92     status = pdev_map_interrupt(&pdev_, IRQ_RDMA, rdma_irq_.reset_and_get_address());
93     if (status != ZX_OK) {
94         DISP_ERROR("Could not map RDMA interrupt\n");
95         return status;
96     }
97 
98     auto start_thread = [](void* arg) {return static_cast<Osd*>(arg)->RdmaThread(); };
99     status = thrd_create_with_name(&rdma_thread_, start_thread, this, "rdma_thread");
100     if (status != ZX_OK) {
101         DISP_ERROR("Could not create rdma_thread\n");
102         return status;
103     }
104 
105     // Setup RDMA
106     status = SetupRdma();
107     if (status != ZX_OK) {
108         DISP_ERROR("Could not setup RDMA\n");
109         return status;
110     }
111 
112     // OSD object is ready to be used.
113     initialized_ = true;
114     return ZX_OK;
115 }
116 
Disable(void)117 void Osd::Disable(void) {
118     ZX_DEBUG_ASSERT(initialized_);
119     // Display RDMA
120     vpu_mmio_->ClearBits32(RDMA_ACCESS_AUTO_INT_EN_ALL, VPU_RDMA_ACCESS_AUTO);
121     vpu_mmio_->ClearBits32(1 << 0, VPU_VIU_OSD1_CTRL_STAT);
122 }
123 
Enable(void)124 void Osd::Enable(void) {
125     ZX_DEBUG_ASSERT(initialized_);
126     vpu_mmio_->SetBits32(1 << 0, VPU_VIU_OSD1_CTRL_STAT);
127 }
128 
Configure()129 zx_status_t Osd::Configure() {
130     // TODO(payamm): OSD for g12a is slightly different from gxl. Currently, uBoot enables
131     // scaling and 16bit mode (565) and configures various layers based on that assumption.
132     // Since we don't have a full end-to-end driver at this moment, we cannot simply turn off
133     // scaling.
134     // For now, we will only configure the OSD layer to use the new Canvas index,
135     // and use 32-bit color.
136     // Set to use BGRX instead of BGRA.
137     vpu_mmio_->SetBits32(VpuViuOsd1CtrlStat2ReplacedAlphaEn |
138                              (0xff << VpuViuOsd1CtrlStat2ReplacedAlphaShift),
139                          VPU_VIU_OSD1_CTRL_STAT2);
140 
141     return ZX_OK;
142 }
143 
FlipOnVsync(uint8_t idx)144 void Osd::FlipOnVsync(uint8_t idx) {
145 
146     // Get the first available channel
147     int rdma_channel = GetNextAvailableRdmaChannel();
148     uint8_t retry_count = 0;
149     while (rdma_channel == -1 && retry_count++ < kMaxRetries) {
150         zx_nanosleep(zx_deadline_after(ZX_USEC(10)));
151         rdma_channel = GetNextAvailableRdmaChannel();
152     }
153 
154     if (rdma_channel < 0) {
155         ZX_DEBUG_ASSERT(false);
156         return;
157     }
158 
159     DISP_SPEW("Channel used is %d\n", rdma_channel);
160 
161     // Update CFG_W0 with correct Canvas Index
162     uint32_t cfg_w0 = (idx << VpuViuOsd1BlkCfgTblAddrShift) |
163         VpuViuOsd1BlkCfgLittleEndian |
164         (VpuViuOsd1BlkCfgOsdBlkMode32Bit << VpuViuOsd1BlkCfgOsdBlkModeShift) |
165         (VpuViuOsd1BlkCfgColorMatrixArgb << VpuViuOsd1BlkCfgColorMatrixShift);
166     SetRdmaTableValue(rdma_channel, IDX_CFG_W0, cfg_w0);
167     SetRdmaTableValue(rdma_channel, IDX_CTRL_STAT,
168                       vpu_mmio_->Read32(VPU_VIU_OSD1_CTRL_STAT) | (1 << 0));
169     FlushRdmaTable(rdma_channel);
170 
171     // Write the start and end address of the table. End address is the last address that the
172     // RDMA engine reads from.
173     vpu_mmio_->Write32(static_cast<uint32_t> (rdma_chnl_container_[rdma_channel].phys_offset),
174                        VPU_RDMA_AHB_START_ADDR(rdma_channel));
175     vpu_mmio_->Write32(static_cast<uint32_t>(rdma_chnl_container_[rdma_channel].phys_offset +
176                        (sizeof(RdmaTable) * kRdmaTableMaxSize) - 4),
177                        VPU_RDMA_AHB_END_ADDR(rdma_channel));
178 
179     // Enable Auto mode: Non-Increment, VSync Interrupt Driven, Write
180     uint32_t regVal = vpu_mmio_->Read32(VPU_RDMA_ACCESS_AUTO);
181     regVal |= RDMA_ACCESS_AUTO_INT_EN(rdma_channel); // VSYNC interrupt source
182     regVal |= RDMA_ACCESS_AUTO_WRITE(rdma_channel); // Write
183     vpu_mmio_->Write32(regVal, VPU_RDMA_ACCESS_AUTO);
184 }
185 
DefaultSetup()186 void Osd::DefaultSetup() {
187     // osd blend ctrl
188     WRITE32_REG(VPU, VIU_OSD_BLEND_CTRL,
189         4 << 29|
190         0 << 27| // blend2_premult_en
191         1 << 26| // blend_din0 input to blend0
192         0 << 25| // blend1_dout to blend2
193         0 << 24| // blend1_din3 input to blend1
194         1 << 20| // blend_din_en
195         0 << 16| // din_premult_en
196         1 << 0); // din_reoder_sel = OSD1
197 
198     // vpp osd1 blend ctrl
199     WRITE32_REG(VPU, OSD1_BLEND_SRC_CTRL,
200         (0 & 0xf) << 0 |
201         (0 & 0x1) << 4 |
202         (3 & 0xf) << 8 | // postbld_src3_sel
203         (0 & 0x1) << 16| // postbld_osd1_premult
204         (1 & 0x1) << 20);
205     // vpp osd2 blend ctrl
206     WRITE32_REG(VPU, OSD2_BLEND_SRC_CTRL,
207         (0 & 0xf) << 0 |
208         (0 & 0x1) << 4 |
209         (0 & 0xf) << 8 | // postbld_src4_sel
210         (0 & 0x1) << 16 | // postbld_osd2_premult
211         (1 & 0x1) << 20);
212 
213     // used default dummy data
214     WRITE32_REG(VPU, VIU_OSD_BLEND_DUMMY_DATA0,
215         0x0 << 16 |
216         0x0 << 8 |
217         0x0);
218     // used default dummy alpha data
219     WRITE32_REG(VPU, VIU_OSD_BLEND_DUMMY_ALPHA,
220         0x0  << 20 |
221         0x0  << 11 |
222         0x0);
223 
224     // osdx setting
225     WRITE32_REG(VPU,
226         VPU_VIU_OSD_BLEND_DIN0_SCOPE_H,
227         (fb_width_ - 1) << 16);
228 
229     WRITE32_REG(VPU,
230         VPU_VIU_OSD_BLEND_DIN0_SCOPE_V,
231         (fb_height_ - 1) << 16);
232 
233     WRITE32_REG(VPU, VIU_OSD_BLEND_BLEND0_SIZE,
234         fb_height_ << 16 |
235         fb_width_);
236     WRITE32_REG(VPU, VIU_OSD_BLEND_BLEND1_SIZE,
237         fb_height_  << 16 |
238         fb_width_);
239     SET_BIT32(VPU, DOLBY_PATH_CTRL, 0x3, 2, 2);
240 
241     WRITE32_REG(VPU, VPP_OSD1_IN_SIZE,
242         fb_height_ << 16 | fb_width_);
243 
244     // setting blend scope
245     WRITE32_REG(VPU, VPP_OSD1_BLD_H_SCOPE,
246         0 << 16 | (fb_width_ - 1));
247     WRITE32_REG(VPU, VPP_OSD1_BLD_V_SCOPE,
248         0 << 16 | (fb_height_ - 1));
249 
250     // Set geometry to normal mode
251     uint32_t data32 = ((fb_width_ - 1) & 0xfff) << 16;
252     WRITE32_REG(VPU, VPU_VIU_OSD1_BLK0_CFG_W3 , data32);
253     data32 = ((fb_height_ - 1) & 0xfff) << 16;
254     WRITE32_REG(VPU, VPU_VIU_OSD1_BLK0_CFG_W4, data32);
255 
256     WRITE32_REG(VPU, VPU_VIU_OSD1_BLK0_CFG_W1, ((fb_width_ - 1) & 0x1fff) << 16);
257     WRITE32_REG(VPU, VPU_VIU_OSD1_BLK0_CFG_W2, ((fb_height_ - 1) & 0x1fff) << 16);
258 
259     // enable osd blk0
260     SET_BIT32(VPU, VPU_VIU_OSD1_CTRL_STAT, kHwOsdBlockEnable0, 0, 4);
261 }
262 
EnableScaling(bool enable)263 void Osd::EnableScaling(bool enable) {
264     int hf_phase_step, vf_phase_step;
265     int src_w, src_h, dst_w, dst_h;
266     int bot_ini_phase;
267     int vsc_ini_rcv_num, vsc_ini_rpt_p0_num;
268     int hsc_ini_rcv_num, hsc_ini_rpt_p0_num;
269     int hf_bank_len = 4;
270     int vf_bank_len = 0;
271     uint32_t data32 = 0x0;
272 
273     vf_bank_len = 4;
274     hsc_ini_rcv_num = hf_bank_len;
275     vsc_ini_rcv_num = vf_bank_len;
276     hsc_ini_rpt_p0_num =
277         (hf_bank_len / 2 - 1) > 0 ? (hf_bank_len / 2 - 1) : 0;
278     vsc_ini_rpt_p0_num =
279         (vf_bank_len / 2 - 1) > 0 ? (vf_bank_len / 2 - 1) : 0;
280     src_w = fb_width_;
281     src_h = fb_height_;
282     dst_w = display_width_;
283     dst_h = display_height_;
284 
285     data32 = 0x0;
286     if (enable) {
287         /* enable osd scaler */
288         data32 |= 1 << 2; /* enable osd scaler */
289         data32 |= 1 << 3; /* enable osd scaler path */
290         WRITE32_REG(VPU, VPU_VPP_OSD_SC_CTRL0, data32);
291     } else {
292         /* disable osd scaler path */
293         WRITE32_REG(VPU, VPU_VPP_OSD_SC_CTRL0, 0);
294     }
295     hf_phase_step = (src_w << 18) / dst_w;
296     hf_phase_step = (hf_phase_step << 6);
297     vf_phase_step = (src_h << 20) / dst_h;
298     bot_ini_phase = 0;
299     vf_phase_step = (vf_phase_step << 4);
300 
301     /* config osd scaler in/out hv size */
302     data32 = 0x0;
303     if (enable) {
304         data32 = (((src_h - 1) & 0x1fff)
305               | ((src_w - 1) & 0x1fff) << 16);
306         WRITE32_REG(VPU, VPU_VPP_OSD_SCI_WH_M1, data32);
307         data32 = (((display_width_ - 1) & 0xfff));
308         WRITE32_REG(VPU, VPU_VPP_OSD_SCO_H_START_END, data32);
309         data32 = (((display_height_ - 1) & 0xfff));
310         WRITE32_REG(VPU, VPU_VPP_OSD_SCO_V_START_END, data32);
311     }
312     data32 = 0x0;
313     if (enable) {
314         data32 |= (vf_bank_len & 0x7)
315               | ((vsc_ini_rcv_num & 0xf) << 3)
316               | ((vsc_ini_rpt_p0_num & 0x3) << 8);
317         data32 |= 1 << 24;
318     }
319     WRITE32_REG(VPU, VPU_VPP_OSD_VSC_CTRL0, data32);
320     data32 = 0x0;
321     if (enable) {
322         data32 |= (hf_bank_len & 0x7)
323               | ((hsc_ini_rcv_num & 0xf) << 3)
324               | ((hsc_ini_rpt_p0_num & 0x3) << 8);
325         data32 |= 1 << 22;
326     }
327     WRITE32_REG(VPU, VPU_VPP_OSD_HSC_CTRL0, data32);
328     data32 = 0x0;
329     if (enable) {
330         data32 |= (bot_ini_phase & 0xffff) << 16;
331         SET_BIT32(VPU,VPU_VPP_OSD_HSC_PHASE_STEP,
332                       hf_phase_step, 0, 28);
333         SET_BIT32(VPU,VPU_VPP_OSD_HSC_INI_PHASE, 0, 0, 16);
334         SET_BIT32(VPU,VPU_VPP_OSD_VSC_PHASE_STEP,
335                       vf_phase_step, 0, 28);
336         WRITE32_REG(VPU, VPU_VPP_OSD_VSC_INI_PHASE, data32);
337     }
338 }
339 
ResetRdmaTable()340 void Osd::ResetRdmaTable() {
341     // For Astro display driver, RDMA table is simple.
342     // Setup RDMA Table Register values
343     for (int i = 0; i < kMaxRdmaChannels; i++) {
344         RdmaTable* rdma_table = reinterpret_cast<RdmaTable*>(rdma_chnl_container_[i].virt_offset);
345         rdma_table[IDX_CFG_W0].reg = (VPU_VIU_OSD1_BLK0_CFG_W0 >> 2);
346         rdma_table[IDX_CTRL_STAT].reg = (VPU_VIU_OSD1_CTRL_STAT >> 2);
347     }
348 
349 }
350 
SetRdmaTableValue(uint32_t channel,uint32_t idx,uint32_t val)351 void Osd::SetRdmaTableValue(uint32_t channel, uint32_t idx, uint32_t val) {
352     ZX_DEBUG_ASSERT(idx < IDX_MAX);
353     ZX_DEBUG_ASSERT(channel < kMaxRdmaChannels);
354     RdmaTable* rdma_table = reinterpret_cast<RdmaTable*>(rdma_chnl_container_[channel].virt_offset);
355     rdma_table[idx].val = val;
356 }
357 
FlushRdmaTable(uint32_t channel)358 void Osd::FlushRdmaTable(uint32_t channel) {
359     zx_status_t status = zx_cache_flush(rdma_chnl_container_[channel].virt_offset,
360                                         sizeof(RdmaTable),
361                                         ZX_CACHE_FLUSH_DATA | ZX_CACHE_FLUSH_INVALIDATE);
362     if (status != ZX_OK) {
363         DISP_ERROR("Could not clean cache %d\n", status);
364         return;
365     }
366 }
367 
GetNextAvailableRdmaChannel()368 int Osd::GetNextAvailableRdmaChannel() {
369     // The next RDMA channel is the one that is not being used by hardware
370     // A channel is considered available if it's not busy OR the done bit is set
371     for (int i = 0; i < kMaxRdmaChannels; i++) {
372         if (!rdma_chnl_container_[i].active ||
373             vpu_mmio_->Read32(VPU_RDMA_STATUS) & RDMA_STATUS_DONE(i)) {
374             // found one
375             rdma_chnl_container_[i].active = true;
376             // clear interrupts
377             vpu_mmio_->Write32(vpu_mmio_->Read32(VPU_RDMA_CTRL) | RDMA_CTRL_INT_DONE(i),
378                                VPU_RDMA_CTRL);
379             return i;
380         }
381     }
382 
383     return -1;
384 }
385 
SetupRdma()386 zx_status_t Osd::SetupRdma() {
387     zx_status_t status = ZX_OK;
388     DISP_INFO("Setting up RDMA\n");
389 
390     // since we are flushing the caches, make sure the tables are at least cache_line apart
391     ZX_DEBUG_ASSERT(kChannelBaseOffset > zx_system_get_dcache_line_size());
392 
393     // Allocate one page for RDMA Table
394     status = zx_vmo_create_contiguous(bti_.get(), ZX_PAGE_SIZE, 0,
395                                                   rdma_vmo_.reset_and_get_address());
396     if (status != ZX_OK) {
397         DISP_ERROR("Could not create RDMA VMO (%d)\n", status);
398         return status;
399     }
400 
401     status = zx_bti_pin(bti_.get(), ZX_BTI_PERM_READ | ZX_BTI_PERM_WRITE, rdma_vmo_.get(),
402                         0, ZX_PAGE_SIZE, &rdma_phys_, 1, &rdma_pmt_);
403     if (status != ZX_OK) {
404         DISP_ERROR("Could not pin RDMA VMO (%d)\n", status);
405         return status;
406     }
407 
408     status = zx_vmar_map(zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
409                          0, rdma_vmo_.get(), 0, ZX_PAGE_SIZE,
410                          reinterpret_cast<zx_vaddr_t*>(&rdma_vbuf_));
411     if (status != ZX_OK) {
412         DISP_ERROR("Could not map vmar (%d)\n", status);
413         return status;
414     }
415 
416     // Initialize each rdma channel container
417     for (int i = 0; i < kMaxRdmaChannels; i++) {
418         ZX_DEBUG_ASSERT((i * kChannelBaseOffset) < ZX_PAGE_SIZE);
419         rdma_chnl_container_[i].phys_offset = rdma_phys_ + (i * kChannelBaseOffset);
420         rdma_chnl_container_[i].virt_offset = rdma_vbuf_ + (i * kChannelBaseOffset);
421         rdma_chnl_container_[i].active = false;
422     }
423 
424     // Setup RDMA_CTRL:
425     // Default: no reset, no clock gating, burst size 4x16B for read and write
426     // DDR Read/Write request urgent
427     uint32_t regVal = RDMA_CTRL_READ_URGENT | RDMA_CTRL_WRITE_URGENT;
428     vpu_mmio_->Write32(regVal, VPU_RDMA_CTRL);
429 
430     ResetRdmaTable();
431 
432     return status;
433 }
434 
HwInit()435 void Osd::HwInit() {
436     ZX_DEBUG_ASSERT(initialized_);
437     // Setup VPP horizontal width
438     WRITE32_REG(VPU, VPP_POSTBLEND_H_SIZE, display_width_);
439 
440     // init vpu fifo control register
441     uint32_t regVal = READ32_REG(VPU, VPP_OFIFO_SIZE);
442     regVal = 0xfff << 20;
443     regVal |= (0xfff + 1);
444     WRITE32_REG(VPU, VPP_OFIFO_SIZE, regVal);
445 
446     // init osd fifo control and set DDR request priority to be urgent
447     regVal = 1;
448     regVal |= 4 << 5; // hold_fifo_lines
449     regVal |= 1 << 10; // burst_len_sel 3 = 64. This bit is split between 10 and 31
450     regVal |= 2 << 22;
451     regVal |= 2 << 24;
452     regVal |= 1 << 31;
453     regVal |= 32 << 12; // fifo_depth_val: 32*8 = 256
454     WRITE32_REG(VPU, VPU_VIU_OSD1_FIFO_CTRL_STAT, regVal);
455     WRITE32_REG(VPU, VPU_VIU_OSD2_FIFO_CTRL_STAT, regVal);
456 
457     SET_MASK32(VPU, VPP_MISC, VPP_POSTBLEND_EN);
458     CLEAR_MASK32(VPU, VPP_MISC, VPP_PREBLEND_EN);
459     // just disable osd to avoid booting hang up
460     regVal = 0x1 << 0;
461     regVal |= kOsdGlobalAlphaDef << 12;
462     regVal |= (1 << 21);
463     WRITE32_REG(VPU, VPU_VIU_OSD1_CTRL_STAT , regVal);
464     WRITE32_REG(VPU, VPU_VIU_OSD2_CTRL_STAT , regVal);
465 
466     DefaultSetup();
467 
468     EnableScaling(true);
469 
470     // Apply scale coefficients
471     SET_BIT32(VPU, VPU_VPP_OSD_SCALE_COEF_IDX, 0x0000, 0, 9);
472     for (int i = 0; i < 33; i++) {
473         WRITE32_REG(VPU, VPU_VPP_OSD_SCALE_COEF, osd_filter_coefs_bicubic[i]);
474     }
475 
476     SET_BIT32(VPU, VPU_VPP_OSD_SCALE_COEF_IDX, 0x0100, 0, 9);
477     for (int i = 0; i < 33; i++) {
478         WRITE32_REG(VPU, VPU_VPP_OSD_SCALE_COEF, osd_filter_coefs_bicubic[i]);
479     }
480 
481     // update blending
482     WRITE32_REG(VPU, VPU_VPP_OSD1_BLD_H_SCOPE, display_width_ - 1);
483     WRITE32_REG(VPU, VPU_VPP_OSD1_BLD_V_SCOPE, display_height_ - 1);
484     WRITE32_REG(VPU, VPU_VPP_OUT_H_V_SIZE, display_width_ << 16 | display_height_);
485 }
486 
487 #define REG_OFFSET (0x20 << 2)
Dump()488 void Osd::Dump() {
489     ZX_DEBUG_ASSERT(initialized_);
490     uint32_t reg = 0;
491     uint32_t offset = 0;
492     uint32_t index = 0;
493 
494     reg = VPU_VIU_VENC_MUX_CTRL;
495     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
496     reg = VPU_VPP_MISC;
497     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
498     reg = VPU_VPP_OFIFO_SIZE;
499     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
500     reg = VPU_VPP_HOLD_LINES;
501     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
502 
503     reg = VPU_OSD_PATH_MISC_CTRL;
504     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
505     reg = VPU_VIU_OSD_BLEND_CTRL;
506     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
507     reg = VPU_VIU_OSD_BLEND_DIN0_SCOPE_H;
508     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
509     reg = VPU_VIU_OSD_BLEND_DIN0_SCOPE_V;
510     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
511     reg = VPU_VIU_OSD_BLEND_DIN1_SCOPE_H;
512     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
513     reg = VPU_VIU_OSD_BLEND_DIN1_SCOPE_V;
514     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
515     reg = VPU_VIU_OSD_BLEND_DIN2_SCOPE_H;
516     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
517     reg = VPU_VIU_OSD_BLEND_DIN2_SCOPE_V;
518     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
519     reg = VPU_VIU_OSD_BLEND_DIN3_SCOPE_H;
520     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
521     reg = VPU_VIU_OSD_BLEND_DIN3_SCOPE_V;
522     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
523     reg = VPU_VIU_OSD_BLEND_DUMMY_DATA0;
524     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
525     reg = VPU_VIU_OSD_BLEND_DUMMY_ALPHA;
526     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
527     reg = VPU_VIU_OSD_BLEND_BLEND0_SIZE;
528     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
529     reg = VPU_VIU_OSD_BLEND_BLEND1_SIZE;
530     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
531 
532     reg = VPU_VPP_OSD1_IN_SIZE;
533     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
534     reg = VPU_VPP_OSD1_BLD_H_SCOPE;
535     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
536     reg = VPU_VPP_OSD1_BLD_V_SCOPE;
537     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
538     reg = VPU_VPP_OSD2_BLD_H_SCOPE;
539     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
540     reg = VPU_VPP_OSD2_BLD_V_SCOPE;
541     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
542     reg = OSD1_BLEND_SRC_CTRL;
543     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
544     reg = OSD2_BLEND_SRC_CTRL;
545     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
546     reg = VPU_VPP_POSTBLEND_H_SIZE;
547     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
548     reg = VPU_VPP_OUT_H_V_SIZE;
549     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
550 
551     reg = VPU_VPP_OSD_SC_CTRL0;
552     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
553     reg = VPU_VPP_OSD_SCI_WH_M1;
554     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
555     reg = VPU_VPP_OSD_SCO_H_START_END;
556     DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
557     reg = VPU_VPP_OSD_SCO_V_START_END;
558     DISP_INFO("reg[0x%x]: 0x%08x\n\n", reg, READ32_REG(VPU, reg));
559     reg = VPU_VPP_POSTBLEND_H_SIZE;
560     DISP_INFO("reg[0x%x]: 0x%08x\n\n", reg, READ32_REG(VPU, reg));
561     for (index = 0; index < 2; index++) {
562         if (index == 1)
563             offset = REG_OFFSET;
564         reg = offset + VPU_VIU_OSD1_FIFO_CTRL_STAT;
565         DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
566         reg = offset + VPU_VIU_OSD1_CTRL_STAT;
567         DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
568         reg = offset + VPU_VIU_OSD1_BLK0_CFG_W0;
569         DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
570         reg = offset + VPU_VIU_OSD1_BLK0_CFG_W1;
571         DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
572         reg = offset + VPU_VIU_OSD1_BLK0_CFG_W2;
573         DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
574         reg = offset + VPU_VIU_OSD1_BLK0_CFG_W3;
575         DISP_INFO("reg[0x%x]: 0x%08x\n", reg, READ32_REG(VPU, reg));
576         reg = VPU_VIU_OSD1_BLK0_CFG_W4;
577         if (index == 1)
578             reg = VPU_VIU_OSD2_BLK0_CFG_W4;
579         DISP_INFO("reg[0x%x]: 0x%08x\n\n", reg, READ32_REG(VPU, reg));
580     }
581 }
582 
Release()583 void Osd::Release() {
584     Disable();
585     rdma_irq_.destroy();
586     thrd_join(rdma_thread_, NULL);
587     zx_pmt_unpin(rdma_pmt_);
588 }
589 
590 } // namespace astro_display
591