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 "astro-clock.h"
6#include <ddk/debug.h>
7
8namespace astro_display {
9
10namespace {
11constexpr uint8_t kMaxPllLockAttempt    = 3;
12constexpr uint8_t kStv2Sel              = 5;
13constexpr uint8_t kStv1Sel              = 4;
14constexpr uint32_t kKHZ                 = 1000;
15} // namespace
16
17#define READ32_HHI_REG(a)                   hhi_regs_->Read<uint32_t>(a)
18#define WRITE32_HHI_REG(a, v)               hhi_regs_->Write<uint32_t>(a, v)
19
20#define READ32_VPU_REG(a)                   vpu_regs_->Read<uint32_t>(a)
21#define WRITE32_VPU_REG(a, v)               vpu_regs_->Write<uint32_t>(a, v)
22
23void AstroDisplayClock::CalculateLcdTiming(const DisplaySetting& d) {
24    // Calculate and store DataEnable horizontal and vertical start/stop times
25    const uint32_t de_hstart = d.h_period - d.h_active - 1;
26    const uint32_t de_vstart = d.v_period - d.v_active;
27    lcd_timing_.vid_pixel_on = de_hstart;
28    lcd_timing_.vid_line_on = de_vstart;
29    lcd_timing_.de_hs_addr = de_hstart;
30    lcd_timing_.de_he_addr = de_hstart + d.h_active;
31    lcd_timing_.de_vs_addr = de_vstart;
32    lcd_timing_.de_ve_addr = de_vstart + d.v_active - 1;
33
34    // Calculate and Store HSync horizontal and vertical start/stop times
35    const uint32_t hstart = (de_hstart + d.h_period - d.hsync_bp - d.hsync_width) % d.h_period;
36    const uint32_t hend = (de_hstart + d.h_period - d.hsync_bp) % d.h_period;
37    lcd_timing_.hs_hs_addr = hstart;
38    lcd_timing_.hs_he_addr = hend;
39    lcd_timing_.hs_vs_addr = 0;
40    lcd_timing_.hs_ve_addr = d.v_period - 1;
41
42    // Calculate and Store VSync horizontal and vertical start/stop times
43    lcd_timing_.vs_hs_addr = (hstart + d.h_period) % d.h_period;
44    lcd_timing_.vs_he_addr = lcd_timing_.vs_hs_addr;
45    const uint32_t vstart = (de_vstart + d.v_period - d.vsync_bp - d.vsync_width) % d.v_period;
46    const uint32_t vend = (de_vstart + d.v_period - d.vsync_bp) % d.v_period;
47    lcd_timing_.vs_vs_addr = vstart;
48    lcd_timing_.vs_ve_addr = vend;
49}
50
51zx_status_t AstroDisplayClock::PllLockWait() {
52    uint32_t pll_lock;
53
54    for (int lock_attempts = 0; lock_attempts < kMaxPllLockAttempt; lock_attempts++) {
55        DISP_SPEW("Waiting for PLL Lock: (%d/3).\n", lock_attempts+1);
56        if (lock_attempts == 1) {
57            SET_BIT32(HHI, HHI_HDMI_PLL_CNTL3, 1, 31, 1);
58        } else if (lock_attempts == 2) {
59            WRITE32_REG(HHI, HHI_HDMI_PLL_CNTL6, 0x55540000); // more magic
60        }
61        int retries = 1000;
62        while ((pll_lock = GET_BIT32(HHI, HHI_HDMI_PLL_CNTL0, LCD_PLL_LOCK_HPLL_G12A, 1)) != 1 &&
63               retries--) {
64            zx_nanosleep(zx_deadline_after(ZX_USEC(50)));
65        }
66        if (pll_lock) {
67            return ZX_OK;
68        }
69    }
70
71    // We got here, which means we never locked!
72    DISP_ERROR("PLL not locked! exiting\n");
73    return ZX_ERR_UNAVAILABLE;
74}
75
76zx_status_t AstroDisplayClock::GenerateHPLL(const DisplaySetting& d) {
77    uint32_t pll_fout;
78    // Requested Pixel clock
79    pll_cfg_.fout = d.lcd_clock / kKHZ; // KHz
80    // Desired PLL Frequency based on pixel clock needed
81    pll_fout = pll_cfg_.fout * d.clock_factor;
82
83    // Make sure all clocks are within range
84    // If these values are not within range, we will not have a valid display
85    if((pll_cfg_.fout > MAX_PIXEL_CLK_KHZ) ||
86       (pll_fout < MIN_PLL_FREQ_KHZ) || (pll_fout > MAX_PLL_FREQ_KHZ)) {
87        DISP_ERROR("Calculated clocks out of range!\n");
88        return ZX_ERR_OUT_OF_RANGE;
89    }
90
91    // Now that we have valid frequency ranges, let's calculated all the PLL-related
92    // multipliers/dividers
93    // [fin] * [m/n] = [pll_vco]
94    // [pll_vco] / [od1] / [od2] / [od3] = pll_fout
95    // [fvco] --->[OD1] --->[OD2] ---> [OD3] --> pll_fout
96    uint32_t od3, od2, od1;
97    od3 = (1 << (MAX_OD_SEL - 1));
98    while (od3) {
99        uint32_t fod3 = pll_fout * od3;
100        od2 = od3;
101        while (od2) {
102            uint32_t fod2 = fod3 * od2;
103            od1 = od2;
104            while (od1) {
105                uint32_t fod1 = fod2 * od1;
106                if ((fod1 >= MIN_PLL_VCO_KHZ) &&
107                    (fod1 <= MAX_PLL_VCO_KHZ)) {
108                    // within range!
109                    pll_cfg_.pll_od1_sel = od1 >> 1;
110                    pll_cfg_.pll_od2_sel = od2 >> 1;
111                    pll_cfg_.pll_od3_sel = od3 >> 1;
112                    pll_cfg_.pll_fout = pll_fout;
113                    DISP_SPEW("od1=%d, od2=%d, od3=%d\n",
114                            (od1 >> 1), (od2 >> 1),
115                            (od3 >> 1));
116                    DISP_SPEW("pll_fvco=%d\n", fod1);
117                    pll_cfg_.pll_fvco = fod1;
118                    // for simplicity, assume n = 1
119                    // calculate m such that fin x m = fod1
120                    uint32_t m;
121                    uint32_t pll_frac;
122                    fod1 = fod1 / 1;
123                    m = fod1 / FIN_FREQ_KHZ;
124                    pll_frac = (fod1 % FIN_FREQ_KHZ) * PLL_FRAC_RANGE / FIN_FREQ_KHZ;
125                    pll_cfg_.pll_m = m;
126                    pll_cfg_.pll_n = 1;
127                    pll_cfg_.pll_frac = pll_frac;
128                    DISP_SPEW("m=%d, n=%d, frac=0x%x\n",
129                            m, 1, pll_frac);
130                    pll_cfg_.bitrate = pll_fout * kKHZ; // Hz
131                    return ZX_OK;
132                }
133                od1 >>= 1;
134            }
135            od2 >>= 1;
136        }
137        od3 >>= 1;
138    }
139
140    DISP_ERROR("Could not generate correct PLL values!\n");
141    return ZX_ERR_INTERNAL;
142}
143
144void AstroDisplayClock::Disable() {
145    ZX_DEBUG_ASSERT(initialized_);
146    if (!clock_enabled_) {
147        return;
148    }
149    WRITE32_REG(VPU, ENCL_VIDEO_EN, 0);
150
151    SET_BIT32(HHI, HHI_VID_CLK_CNTL2, 0, ENCL_GATE_VCLK, 1);
152    SET_BIT32(HHI, HHI_VIID_CLK_CNTL, 0, 0, 5);
153    SET_BIT32(HHI, HHI_VIID_CLK_CNTL, 0, VCLK2_EN, 1);
154
155    // disable pll
156    SET_BIT32(HHI, HHI_HDMI_PLL_CNTL0, 0, LCD_PLL_EN_HPLL_G12A, 1);
157    clock_enabled_ = false;
158}
159
160zx_status_t AstroDisplayClock::Enable(const DisplaySetting& d) {
161    ZX_DEBUG_ASSERT(initialized_);
162
163    if (clock_enabled_) {
164        return ZX_OK;
165    }
166
167    // Populate internal LCD timing structure based on predefined tables
168    CalculateLcdTiming(d);
169    GenerateHPLL(d);
170
171    uint32_t regVal;
172    PllConfig* pll_cfg = &pll_cfg_;
173    bool useFrac = !!pll_cfg->pll_frac;
174
175    regVal = ((1 << LCD_PLL_EN_HPLL_G12A) |
176             (1 << LCD_PLL_OUT_GATE_CTRL_G12A) | // clk out gate
177             (pll_cfg->pll_n << LCD_PLL_N_HPLL_G12A) |
178             (pll_cfg->pll_m << LCD_PLL_M_HPLL_G12A) |
179             (pll_cfg->pll_od1_sel << LCD_PLL_OD1_HPLL_G12A) |
180             (pll_cfg->pll_od2_sel << LCD_PLL_OD2_HPLL_G12A) |
181             (pll_cfg->pll_od3_sel << LCD_PLL_OD3_HPLL_G12A) |
182             (useFrac? (1 << 27) : (0 << 27)));
183    WRITE32_REG(HHI, HHI_HDMI_PLL_CNTL0, regVal);
184
185    WRITE32_REG(HHI, HHI_HDMI_PLL_CNTL1, pll_cfg->pll_frac);
186    WRITE32_REG(HHI, HHI_HDMI_PLL_CNTL2, 0x00);
187    // Magic numbers from U-Boot.
188    WRITE32_REG(HHI, HHI_HDMI_PLL_CNTL3, useFrac? 0x6a285c00 : 0x48681c00);
189    WRITE32_REG(HHI, HHI_HDMI_PLL_CNTL4, useFrac? 0x65771290 : 0x33771290);
190    WRITE32_REG(HHI, HHI_HDMI_PLL_CNTL5, 0x39272000);
191    WRITE32_REG(HHI, HHI_HDMI_PLL_CNTL6, useFrac? 0x56540000 : 0x56540000);
192
193    // reset dpll
194    SET_BIT32(HHI, HHI_HDMI_PLL_CNTL0, 1, LCD_PLL_RST_HPLL_G12A, 1);
195    zx_nanosleep(zx_deadline_after(ZX_USEC(100)));
196    // release from reset
197    SET_BIT32(HHI, HHI_HDMI_PLL_CNTL0, 0, LCD_PLL_RST_HPLL_G12A, 1);
198
199    zx_nanosleep(zx_deadline_after(ZX_USEC(50)));
200    zx_status_t status = PllLockWait();
201    if (status != ZX_OK) {
202        DISP_ERROR("hpll lock failed\n");
203        io_buffer_release(&mmio_vpu_);
204        io_buffer_release(&mmio_hhi_);
205        return status;
206    }
207
208    // Enable VIID Clock (whatever that is)
209    SET_BIT32(HHI, HHI_VIID_CLK_CNTL, 0, VCLK2_EN, 1);
210    zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
211
212    // Disable the div output clock
213    SET_BIT32(HHI, HHI_VID_PLL_CLK_DIV, 0, 19, 1);
214    SET_BIT32(HHI, HHI_VID_PLL_CLK_DIV, 0, 15, 1);
215
216    SET_BIT32(HHI, HHI_VID_PLL_CLK_DIV, 1, 18, 1); // Undocumented register bit
217
218    // Enable the final output clock
219    SET_BIT32(HHI, HHI_VID_PLL_CLK_DIV, 1, 19, 1); // Undocumented register bit
220
221    // Undocumented register bits
222    SET_BIT32(HHI, HHI_VDIN_MEAS_CLK_CNTL, 0, 21, 3);
223    SET_BIT32(HHI, HHI_VDIN_MEAS_CLK_CNTL, 0, 12, 7);
224    SET_BIT32(HHI, HHI_VDIN_MEAS_CLK_CNTL, 1, 20, 1);
225
226    // USE VID_PLL
227    SET_BIT32(HHI, HHI_MIPIDSI_PHY_CLK_CNTL, 0, 12, 3);
228    // enable dsi_phy_clk
229    SET_BIT32(HHI, HHI_MIPIDSI_PHY_CLK_CNTL, 1, 8, 1);
230    // set divider to 0 -- undocumented
231    SET_BIT32(HHI, HHI_MIPIDSI_PHY_CLK_CNTL, 0, 0, 7);
232
233        // setup the XD divider value
234    SET_BIT32(HHI, HHI_VIID_CLK_DIV, (d.clock_factor-1), VCLK2_XD, 8);
235    zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
236
237    // select vid_pll_clk
238    SET_BIT32(HHI, HHI_VIID_CLK_CNTL, 0, VCLK2_CLK_IN_SEL, 3);
239    SET_BIT32(HHI, HHI_VIID_CLK_CNTL, 1, VCLK2_EN, 1);
240    zx_nanosleep(zx_deadline_after(ZX_USEC(2)));
241
242    // [15:12] encl_clk_sel, select vclk2_div1
243    SET_BIT32(HHI, HHI_VIID_CLK_DIV, 8, ENCL_CLK_SEL, 4);
244    // release vclk2_div_reset and enable vclk2_div
245    SET_BIT32(HHI, HHI_VIID_CLK_DIV, 1, VCLK2_XD_EN, 2);
246    zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
247
248    SET_BIT32(HHI, HHI_VIID_CLK_CNTL, 1, VCLK2_DIV1_EN, 1);
249    SET_BIT32(HHI, HHI_VIID_CLK_CNTL, 1, VCLK2_SOFT_RST, 1);
250    zx_nanosleep(zx_deadline_after(ZX_USEC(10)));
251    SET_BIT32(HHI, HHI_VIID_CLK_CNTL, 0, VCLK2_SOFT_RST, 1);
252    zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
253
254    // enable CTS_ENCL clk gate
255    SET_BIT32(HHI, HHI_VID_CLK_CNTL2, 1, ENCL_GATE_VCLK, 1);
256
257    zx_nanosleep(zx_deadline_after(ZX_MSEC(10)));
258
259    WRITE32_REG(VPU, ENCL_VIDEO_EN, 0);
260
261    // connect both VIUs (Video Input Units) to LCD LVDS Encoders
262    WRITE32_REG(VPU, VPU_VIU_VENC_MUX_CTRL, (0 << 0) | (0 << 2)); //TODO(payamm): macros
263
264    // Undocumented registers below
265    WRITE32_REG(VPU, ENCL_VIDEO_MODE, 0x8000); // bit[15] shadown en
266    WRITE32_REG(VPU, ENCL_VIDEO_MODE_ADV, 0x0418); // Sampling rate: 1
267
268    // bypass filter -- Undocumented registers
269    WRITE32_REG(VPU, ENCL_VIDEO_FILT_CTRL, 0x1000);
270    WRITE32_REG(VPU, ENCL_VIDEO_MAX_PXCNT,  d.h_period - 1);
271    WRITE32_REG(VPU, ENCL_VIDEO_MAX_LNCNT, d.v_period - 1);
272    WRITE32_REG(VPU, ENCL_VIDEO_HAVON_BEGIN, lcd_timing_.vid_pixel_on);
273    WRITE32_REG(VPU, ENCL_VIDEO_HAVON_END,   d.h_active - 1 + lcd_timing_.vid_pixel_on);
274    WRITE32_REG(VPU, ENCL_VIDEO_VAVON_BLINE, lcd_timing_.vid_line_on);
275    WRITE32_REG(VPU, ENCL_VIDEO_VAVON_ELINE, d.v_active - 1  + lcd_timing_.vid_line_on);
276    WRITE32_REG(VPU, ENCL_VIDEO_HSO_BEGIN, lcd_timing_.hs_hs_addr);
277    WRITE32_REG(VPU, ENCL_VIDEO_HSO_END,   lcd_timing_.hs_he_addr);
278    WRITE32_REG(VPU, ENCL_VIDEO_VSO_BEGIN, lcd_timing_.vs_hs_addr);
279    WRITE32_REG(VPU, ENCL_VIDEO_VSO_END,   lcd_timing_.vs_he_addr);
280    WRITE32_REG(VPU, ENCL_VIDEO_VSO_BLINE, lcd_timing_.vs_vs_addr);
281    WRITE32_REG(VPU, ENCL_VIDEO_VSO_ELINE, lcd_timing_.vs_ve_addr);
282    WRITE32_REG(VPU, ENCL_VIDEO_RGBIN_CTRL, 3);
283    WRITE32_REG(VPU, ENCL_VIDEO_EN, 1);
284
285    WRITE32_REG(VPU, L_RGB_BASE_ADDR, 0);
286    WRITE32_REG(VPU, L_RGB_COEFF_ADDR, 0x400);
287    WRITE32_REG(VPU, L_DITH_CNTL_ADDR,  0x400);
288
289    // DE signal for TTL m8,m8m2
290    WRITE32_REG(VPU, L_OEH_HS_ADDR, lcd_timing_.de_hs_addr);
291    WRITE32_REG(VPU, L_OEH_HE_ADDR, lcd_timing_.de_he_addr);
292    WRITE32_REG(VPU, L_OEH_VS_ADDR, lcd_timing_.de_vs_addr);
293    WRITE32_REG(VPU, L_OEH_VE_ADDR, lcd_timing_.de_ve_addr);
294    // DE signal for TTL m8b
295    WRITE32_REG(VPU, L_OEV1_HS_ADDR,  lcd_timing_.de_hs_addr);
296    WRITE32_REG(VPU, L_OEV1_HE_ADDR,  lcd_timing_.de_he_addr);
297    WRITE32_REG(VPU, L_OEV1_VS_ADDR,  lcd_timing_.de_vs_addr);
298    WRITE32_REG(VPU, L_OEV1_VE_ADDR,  lcd_timing_.de_ve_addr);
299
300    // Hsync signal for TTL m8,m8m2
301    if (d.hsync_pol == 0) {
302        WRITE32_REG(VPU, L_STH1_HS_ADDR, lcd_timing_.hs_he_addr);
303        WRITE32_REG(VPU, L_STH1_HE_ADDR, lcd_timing_.hs_hs_addr);
304    } else {
305        WRITE32_REG(VPU, L_STH1_HS_ADDR, lcd_timing_.hs_hs_addr);
306        WRITE32_REG(VPU, L_STH1_HE_ADDR, lcd_timing_.hs_he_addr);
307    }
308    WRITE32_REG(VPU, L_STH1_VS_ADDR, lcd_timing_.hs_vs_addr);
309    WRITE32_REG(VPU, L_STH1_VE_ADDR, lcd_timing_.hs_ve_addr);
310
311    // Vsync signal for TTL m8,m8m2
312    WRITE32_REG(VPU, L_STV1_HS_ADDR, lcd_timing_.vs_hs_addr);
313    WRITE32_REG(VPU, L_STV1_HE_ADDR, lcd_timing_.vs_he_addr);
314    if (d.vsync_pol == 0) {
315        WRITE32_REG(VPU, L_STV1_VS_ADDR, lcd_timing_.vs_ve_addr);
316        WRITE32_REG(VPU, L_STV1_VE_ADDR, lcd_timing_.vs_vs_addr);
317    } else {
318        WRITE32_REG(VPU, L_STV1_VS_ADDR, lcd_timing_.vs_vs_addr);
319        WRITE32_REG(VPU, L_STV1_VE_ADDR, lcd_timing_.vs_ve_addr);
320    }
321
322    // DE signal
323    WRITE32_REG(VPU, L_DE_HS_ADDR,    lcd_timing_.de_hs_addr);
324    WRITE32_REG(VPU, L_DE_HE_ADDR,    lcd_timing_.de_he_addr);
325    WRITE32_REG(VPU, L_DE_VS_ADDR,    lcd_timing_.de_vs_addr);
326    WRITE32_REG(VPU, L_DE_VE_ADDR,    lcd_timing_.de_ve_addr);
327
328    // Hsync signal
329    WRITE32_REG(VPU, L_HSYNC_HS_ADDR,  lcd_timing_.hs_hs_addr);
330    WRITE32_REG(VPU, L_HSYNC_HE_ADDR,  lcd_timing_.hs_he_addr);
331    WRITE32_REG(VPU, L_HSYNC_VS_ADDR,  lcd_timing_.hs_vs_addr);
332    WRITE32_REG(VPU, L_HSYNC_VE_ADDR,  lcd_timing_.hs_ve_addr);
333
334    // Vsync signal
335    WRITE32_REG(VPU, L_VSYNC_HS_ADDR,  lcd_timing_.vs_hs_addr);
336    WRITE32_REG(VPU, L_VSYNC_HE_ADDR,  lcd_timing_.vs_he_addr);
337    WRITE32_REG(VPU, L_VSYNC_VS_ADDR,  lcd_timing_.vs_vs_addr);
338    WRITE32_REG(VPU, L_VSYNC_VE_ADDR,  lcd_timing_.vs_ve_addr);
339
340    WRITE32_REG(VPU, L_INV_CNT_ADDR, 0);
341    WRITE32_REG(VPU, L_TCON_MISC_SEL_ADDR, ((1 << kStv1Sel) | (1 << kStv2Sel)));
342
343    WRITE32_REG(VPU, VPP_MISC, READ32_REG(VPU, VPP_MISC) & ~(VPP_OUT_SATURATE));
344
345    // Ready to be used
346    clock_enabled_ = true;
347    return ZX_OK;
348}
349
350zx_status_t AstroDisplayClock::Init(zx_device_t* parent) {
351    if (initialized_) {
352        return ZX_OK;
353    }
354
355    zx_status_t status = device_get_protocol(parent, ZX_PROTOCOL_PLATFORM_DEV, &pdev_);
356    if (status != ZX_OK) {
357        DISP_ERROR("AstroDisplayClock: Could not get ZX_PROTOCOL_PLATFORM_DEV protocol\n");
358        return status;
359    }
360
361    // Map VPU and HHI registers
362    status = pdev_map_mmio_buffer(&pdev_, MMIO_VPU, ZX_CACHE_POLICY_UNCACHED_DEVICE,
363                                  &mmio_vpu_);
364    if (status != ZX_OK) {
365        DISP_ERROR("AstroDisplayClock: Could not map VPU mmio\n");
366        return status;
367    }
368    status = pdev_map_mmio_buffer(&pdev_, MMIO_HHI, ZX_CACHE_POLICY_UNCACHED_DEVICE,
369                                  &mmio_hhi_);
370    if (status != ZX_OK) {
371        DISP_ERROR("AstroDisplayClock: Could not map HHI mmio\n");
372        io_buffer_release(&mmio_vpu_);
373        return status;
374    }
375
376    // Create register io
377    vpu_regs_ = fbl::make_unique<hwreg::RegisterIo>(io_buffer_virt(&mmio_vpu_));
378    hhi_regs_ = fbl::make_unique<hwreg::RegisterIo>(io_buffer_virt(&mmio_hhi_));
379
380    initialized_ = true;
381    return ZX_OK;
382}
383
384void AstroDisplayClock::Dump() {
385    ZX_DEBUG_ASSERT(initialized_);
386    DISP_INFO("#############################\n");
387    DISP_INFO("Dumping pll_cfg structure:\n");
388    DISP_INFO("#############################\n");
389    DISP_INFO("fin = 0x%x (%u)\n", pll_cfg_.fin,pll_cfg_.fin);
390    DISP_INFO("fout = 0x%x (%u)\n", pll_cfg_.fout,pll_cfg_.fout);
391    DISP_INFO("pll_m = 0x%x (%u)\n", pll_cfg_.pll_m,pll_cfg_.pll_m);
392    DISP_INFO("pll_n = 0x%x (%u)\n", pll_cfg_.pll_n,pll_cfg_.pll_n);
393    DISP_INFO("pll_fvco = 0x%x (%u)\n", pll_cfg_.pll_fvco,pll_cfg_.pll_fvco);
394    DISP_INFO("pll_od1_sel = 0x%x (%u)\n", pll_cfg_.pll_od1_sel,
395              pll_cfg_.pll_od1_sel);
396    DISP_INFO("pll_od2_sel = 0x%x (%u)\n", pll_cfg_.pll_od2_sel,
397              pll_cfg_.pll_od2_sel);
398    DISP_INFO("pll_od3_sel = 0x%x (%u)\n", pll_cfg_.pll_od3_sel,
399              pll_cfg_.pll_od3_sel);
400    DISP_INFO("pll_frac = 0x%x (%u)\n", pll_cfg_.pll_frac,pll_cfg_.pll_frac);
401    DISP_INFO("pll_fout = 0x%x (%u)\n", pll_cfg_.pll_fout,pll_cfg_.pll_fout);
402
403    DISP_INFO("#############################\n");
404    DISP_INFO("Dumping lcd_timing structure:\n");
405    DISP_INFO("#############################\n");
406    DISP_INFO("vid_pixel_on = 0x%x (%u)\n", lcd_timing_.vid_pixel_on,
407              lcd_timing_.vid_pixel_on);
408    DISP_INFO("vid_line_on = 0x%x (%u)\n", lcd_timing_.vid_line_on,
409              lcd_timing_.vid_line_on);
410    DISP_INFO("de_hs_addr = 0x%x (%u)\n", lcd_timing_.de_hs_addr,
411              lcd_timing_.de_hs_addr);
412    DISP_INFO("de_he_addr = 0x%x (%u)\n", lcd_timing_.de_he_addr,
413              lcd_timing_.de_he_addr);
414    DISP_INFO("de_vs_addr = 0x%x (%u)\n", lcd_timing_.de_vs_addr,
415              lcd_timing_.de_vs_addr);
416    DISP_INFO("de_ve_addr = 0x%x (%u)\n", lcd_timing_.de_ve_addr,
417              lcd_timing_.de_ve_addr);
418    DISP_INFO("hs_hs_addr = 0x%x (%u)\n", lcd_timing_.hs_hs_addr,
419              lcd_timing_.hs_hs_addr);
420    DISP_INFO("hs_he_addr = 0x%x (%u)\n", lcd_timing_.hs_he_addr,
421              lcd_timing_.hs_he_addr);
422    DISP_INFO("hs_vs_addr = 0x%x (%u)\n", lcd_timing_.hs_vs_addr,
423              lcd_timing_.hs_vs_addr);
424    DISP_INFO("hs_ve_addr = 0x%x (%u)\n", lcd_timing_.hs_ve_addr,
425              lcd_timing_.hs_ve_addr);
426    DISP_INFO("vs_hs_addr = 0x%x (%u)\n", lcd_timing_.vs_hs_addr,
427              lcd_timing_.vs_hs_addr);
428    DISP_INFO("vs_he_addr = 0x%x (%u)\n", lcd_timing_.vs_he_addr,
429              lcd_timing_.vs_he_addr);
430    DISP_INFO("vs_vs_addr = 0x%x (%u)\n", lcd_timing_.vs_vs_addr,
431              lcd_timing_.vs_vs_addr);
432    DISP_INFO("vs_ve_addr = 0x%x (%u)\n", lcd_timing_.vs_ve_addr,
433              lcd_timing_.vs_ve_addr);
434}
435
436} // namespace astro_display
437