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 
8 namespace astro_display {
9 
10 namespace {
11 constexpr uint8_t kMaxPllLockAttempt    = 3;
12 constexpr uint8_t kStv2Sel              = 5;
13 constexpr uint8_t kStv1Sel              = 4;
14 constexpr uint32_t kKHZ                 = 1000;
15 } // namespace
16 
17 #define READ32_HHI_REG(a)                   hhi_mmio_->Read32(a)
18 #define WRITE32_HHI_REG(a, v)               hhi_mmio_->Write32(v, a)
19 
20 #define READ32_VPU_REG(a)                   vpu_mmio_->Read32(a)
21 #define WRITE32_VPU_REG(a, v)               vpu_mmio_->Write32(v, a)
22 
CalculateLcdTiming(const DisplaySetting & d)23 void 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 
PllLockWait()51 zx_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 
GenerateHPLL(const DisplaySetting & d)76 zx_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 
Disable()144 void 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 
Enable(const DisplaySetting & d)160 zx_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         return status;
204     }
205 
206     // Enable VIID Clock (whatever that is)
207     SET_BIT32(HHI, HHI_VIID_CLK_CNTL, 0, VCLK2_EN, 1);
208     zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
209 
210     // Disable the div output clock
211     SET_BIT32(HHI, HHI_VID_PLL_CLK_DIV, 0, 19, 1);
212     SET_BIT32(HHI, HHI_VID_PLL_CLK_DIV, 0, 15, 1);
213 
214     SET_BIT32(HHI, HHI_VID_PLL_CLK_DIV, 1, 18, 1); // Undocumented register bit
215 
216     // Enable the final output clock
217     SET_BIT32(HHI, HHI_VID_PLL_CLK_DIV, 1, 19, 1); // Undocumented register bit
218 
219     // Undocumented register bits
220     SET_BIT32(HHI, HHI_VDIN_MEAS_CLK_CNTL, 0, 21, 3);
221     SET_BIT32(HHI, HHI_VDIN_MEAS_CLK_CNTL, 0, 12, 7);
222     SET_BIT32(HHI, HHI_VDIN_MEAS_CLK_CNTL, 1, 20, 1);
223 
224     // USE VID_PLL
225     SET_BIT32(HHI, HHI_MIPIDSI_PHY_CLK_CNTL, 0, 12, 3);
226     // enable dsi_phy_clk
227     SET_BIT32(HHI, HHI_MIPIDSI_PHY_CLK_CNTL, 1, 8, 1);
228     // set divider to 0 -- undocumented
229     SET_BIT32(HHI, HHI_MIPIDSI_PHY_CLK_CNTL, 0, 0, 7);
230 
231         // setup the XD divider value
232     SET_BIT32(HHI, HHI_VIID_CLK_DIV, (d.clock_factor-1), VCLK2_XD, 8);
233     zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
234 
235     // select vid_pll_clk
236     SET_BIT32(HHI, HHI_VIID_CLK_CNTL, 0, VCLK2_CLK_IN_SEL, 3);
237     SET_BIT32(HHI, HHI_VIID_CLK_CNTL, 1, VCLK2_EN, 1);
238     zx_nanosleep(zx_deadline_after(ZX_USEC(2)));
239 
240     // [15:12] encl_clk_sel, select vclk2_div1
241     SET_BIT32(HHI, HHI_VIID_CLK_DIV, 8, ENCL_CLK_SEL, 4);
242     // release vclk2_div_reset and enable vclk2_div
243     SET_BIT32(HHI, HHI_VIID_CLK_DIV, 1, VCLK2_XD_EN, 2);
244     zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
245 
246     SET_BIT32(HHI, HHI_VIID_CLK_CNTL, 1, VCLK2_DIV1_EN, 1);
247     SET_BIT32(HHI, HHI_VIID_CLK_CNTL, 1, VCLK2_SOFT_RST, 1);
248     zx_nanosleep(zx_deadline_after(ZX_USEC(10)));
249     SET_BIT32(HHI, HHI_VIID_CLK_CNTL, 0, VCLK2_SOFT_RST, 1);
250     zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
251 
252     // enable CTS_ENCL clk gate
253     SET_BIT32(HHI, HHI_VID_CLK_CNTL2, 1, ENCL_GATE_VCLK, 1);
254 
255     zx_nanosleep(zx_deadline_after(ZX_MSEC(10)));
256 
257     WRITE32_REG(VPU, ENCL_VIDEO_EN, 0);
258 
259     // connect both VIUs (Video Input Units) to LCD LVDS Encoders
260     WRITE32_REG(VPU, VPU_VIU_VENC_MUX_CTRL, (0 << 0) | (0 << 2)); //TODO(payamm): macros
261 
262     // Undocumented registers below
263     WRITE32_REG(VPU, ENCL_VIDEO_MODE, 0x8000); // bit[15] shadown en
264     WRITE32_REG(VPU, ENCL_VIDEO_MODE_ADV, 0x0418); // Sampling rate: 1
265 
266     // bypass filter -- Undocumented registers
267     WRITE32_REG(VPU, ENCL_VIDEO_FILT_CTRL, 0x1000);
268     WRITE32_REG(VPU, ENCL_VIDEO_MAX_PXCNT,  d.h_period - 1);
269     WRITE32_REG(VPU, ENCL_VIDEO_MAX_LNCNT, d.v_period - 1);
270     WRITE32_REG(VPU, ENCL_VIDEO_HAVON_BEGIN, lcd_timing_.vid_pixel_on);
271     WRITE32_REG(VPU, ENCL_VIDEO_HAVON_END,   d.h_active - 1 + lcd_timing_.vid_pixel_on);
272     WRITE32_REG(VPU, ENCL_VIDEO_VAVON_BLINE, lcd_timing_.vid_line_on);
273     WRITE32_REG(VPU, ENCL_VIDEO_VAVON_ELINE, d.v_active - 1  + lcd_timing_.vid_line_on);
274     WRITE32_REG(VPU, ENCL_VIDEO_HSO_BEGIN, lcd_timing_.hs_hs_addr);
275     WRITE32_REG(VPU, ENCL_VIDEO_HSO_END,   lcd_timing_.hs_he_addr);
276     WRITE32_REG(VPU, ENCL_VIDEO_VSO_BEGIN, lcd_timing_.vs_hs_addr);
277     WRITE32_REG(VPU, ENCL_VIDEO_VSO_END,   lcd_timing_.vs_he_addr);
278     WRITE32_REG(VPU, ENCL_VIDEO_VSO_BLINE, lcd_timing_.vs_vs_addr);
279     WRITE32_REG(VPU, ENCL_VIDEO_VSO_ELINE, lcd_timing_.vs_ve_addr);
280     WRITE32_REG(VPU, ENCL_VIDEO_RGBIN_CTRL, 3);
281     WRITE32_REG(VPU, ENCL_VIDEO_EN, 1);
282 
283     WRITE32_REG(VPU, L_RGB_BASE_ADDR, 0);
284     WRITE32_REG(VPU, L_RGB_COEFF_ADDR, 0x400);
285     WRITE32_REG(VPU, L_DITH_CNTL_ADDR,  0x400);
286 
287     // DE signal for TTL m8,m8m2
288     WRITE32_REG(VPU, L_OEH_HS_ADDR, lcd_timing_.de_hs_addr);
289     WRITE32_REG(VPU, L_OEH_HE_ADDR, lcd_timing_.de_he_addr);
290     WRITE32_REG(VPU, L_OEH_VS_ADDR, lcd_timing_.de_vs_addr);
291     WRITE32_REG(VPU, L_OEH_VE_ADDR, lcd_timing_.de_ve_addr);
292     // DE signal for TTL m8b
293     WRITE32_REG(VPU, L_OEV1_HS_ADDR,  lcd_timing_.de_hs_addr);
294     WRITE32_REG(VPU, L_OEV1_HE_ADDR,  lcd_timing_.de_he_addr);
295     WRITE32_REG(VPU, L_OEV1_VS_ADDR,  lcd_timing_.de_vs_addr);
296     WRITE32_REG(VPU, L_OEV1_VE_ADDR,  lcd_timing_.de_ve_addr);
297 
298     // Hsync signal for TTL m8,m8m2
299     if (d.hsync_pol == 0) {
300         WRITE32_REG(VPU, L_STH1_HS_ADDR, lcd_timing_.hs_he_addr);
301         WRITE32_REG(VPU, L_STH1_HE_ADDR, lcd_timing_.hs_hs_addr);
302     } else {
303         WRITE32_REG(VPU, L_STH1_HS_ADDR, lcd_timing_.hs_hs_addr);
304         WRITE32_REG(VPU, L_STH1_HE_ADDR, lcd_timing_.hs_he_addr);
305     }
306     WRITE32_REG(VPU, L_STH1_VS_ADDR, lcd_timing_.hs_vs_addr);
307     WRITE32_REG(VPU, L_STH1_VE_ADDR, lcd_timing_.hs_ve_addr);
308 
309     // Vsync signal for TTL m8,m8m2
310     WRITE32_REG(VPU, L_STV1_HS_ADDR, lcd_timing_.vs_hs_addr);
311     WRITE32_REG(VPU, L_STV1_HE_ADDR, lcd_timing_.vs_he_addr);
312     if (d.vsync_pol == 0) {
313         WRITE32_REG(VPU, L_STV1_VS_ADDR, lcd_timing_.vs_ve_addr);
314         WRITE32_REG(VPU, L_STV1_VE_ADDR, lcd_timing_.vs_vs_addr);
315     } else {
316         WRITE32_REG(VPU, L_STV1_VS_ADDR, lcd_timing_.vs_vs_addr);
317         WRITE32_REG(VPU, L_STV1_VE_ADDR, lcd_timing_.vs_ve_addr);
318     }
319 
320     // DE signal
321     WRITE32_REG(VPU, L_DE_HS_ADDR,    lcd_timing_.de_hs_addr);
322     WRITE32_REG(VPU, L_DE_HE_ADDR,    lcd_timing_.de_he_addr);
323     WRITE32_REG(VPU, L_DE_VS_ADDR,    lcd_timing_.de_vs_addr);
324     WRITE32_REG(VPU, L_DE_VE_ADDR,    lcd_timing_.de_ve_addr);
325 
326     // Hsync signal
327     WRITE32_REG(VPU, L_HSYNC_HS_ADDR,  lcd_timing_.hs_hs_addr);
328     WRITE32_REG(VPU, L_HSYNC_HE_ADDR,  lcd_timing_.hs_he_addr);
329     WRITE32_REG(VPU, L_HSYNC_VS_ADDR,  lcd_timing_.hs_vs_addr);
330     WRITE32_REG(VPU, L_HSYNC_VE_ADDR,  lcd_timing_.hs_ve_addr);
331 
332     // Vsync signal
333     WRITE32_REG(VPU, L_VSYNC_HS_ADDR,  lcd_timing_.vs_hs_addr);
334     WRITE32_REG(VPU, L_VSYNC_HE_ADDR,  lcd_timing_.vs_he_addr);
335     WRITE32_REG(VPU, L_VSYNC_VS_ADDR,  lcd_timing_.vs_vs_addr);
336     WRITE32_REG(VPU, L_VSYNC_VE_ADDR,  lcd_timing_.vs_ve_addr);
337 
338     WRITE32_REG(VPU, L_INV_CNT_ADDR, 0);
339     WRITE32_REG(VPU, L_TCON_MISC_SEL_ADDR, ((1 << kStv1Sel) | (1 << kStv2Sel)));
340 
341     WRITE32_REG(VPU, VPP_MISC, READ32_REG(VPU, VPP_MISC) & ~(VPP_OUT_SATURATE));
342 
343     // Ready to be used
344     clock_enabled_ = true;
345     return ZX_OK;
346 }
347 
Init(zx_device_t * parent)348 zx_status_t AstroDisplayClock::Init(zx_device_t* parent) {
349     if (initialized_) {
350         return ZX_OK;
351     }
352 
353     zx_status_t status = device_get_protocol(parent, ZX_PROTOCOL_PDEV, &pdev_);
354     if (status != ZX_OK) {
355         DISP_ERROR("AstroDisplayClock: Could not get ZX_PROTOCOL_PDEV protocol\n");
356         return status;
357     }
358 
359     // Map VPU and HHI registers
360     mmio_buffer_t mmio;
361     status = pdev_map_mmio_buffer2(&pdev_, MMIO_VPU, ZX_CACHE_POLICY_UNCACHED_DEVICE,
362                                   &mmio);
363     if (status != ZX_OK) {
364         DISP_ERROR("AstroDisplayClock: Could not map VPU mmio\n");
365         return status;
366     }
367     vpu_mmio_ = ddk::MmioBuffer(mmio);
368 
369     status = pdev_map_mmio_buffer2(&pdev_, MMIO_HHI, ZX_CACHE_POLICY_UNCACHED_DEVICE,
370                                   &mmio);
371     if (status != ZX_OK) {
372         DISP_ERROR("AstroDisplayClock: Could not map HHI mmio\n");
373         return status;
374     }
375     hhi_mmio_ = ddk::MmioBuffer(mmio);
376 
377     initialized_ = true;
378     return ZX_OK;
379 }
380 
Dump()381 void AstroDisplayClock::Dump() {
382     ZX_DEBUG_ASSERT(initialized_);
383     DISP_INFO("#############################\n");
384     DISP_INFO("Dumping pll_cfg structure:\n");
385     DISP_INFO("#############################\n");
386     DISP_INFO("fin = 0x%x (%u)\n", pll_cfg_.fin,pll_cfg_.fin);
387     DISP_INFO("fout = 0x%x (%u)\n", pll_cfg_.fout,pll_cfg_.fout);
388     DISP_INFO("pll_m = 0x%x (%u)\n", pll_cfg_.pll_m,pll_cfg_.pll_m);
389     DISP_INFO("pll_n = 0x%x (%u)\n", pll_cfg_.pll_n,pll_cfg_.pll_n);
390     DISP_INFO("pll_fvco = 0x%x (%u)\n", pll_cfg_.pll_fvco,pll_cfg_.pll_fvco);
391     DISP_INFO("pll_od1_sel = 0x%x (%u)\n", pll_cfg_.pll_od1_sel,
392               pll_cfg_.pll_od1_sel);
393     DISP_INFO("pll_od2_sel = 0x%x (%u)\n", pll_cfg_.pll_od2_sel,
394               pll_cfg_.pll_od2_sel);
395     DISP_INFO("pll_od3_sel = 0x%x (%u)\n", pll_cfg_.pll_od3_sel,
396               pll_cfg_.pll_od3_sel);
397     DISP_INFO("pll_frac = 0x%x (%u)\n", pll_cfg_.pll_frac,pll_cfg_.pll_frac);
398     DISP_INFO("pll_fout = 0x%x (%u)\n", pll_cfg_.pll_fout,pll_cfg_.pll_fout);
399 
400     DISP_INFO("#############################\n");
401     DISP_INFO("Dumping lcd_timing structure:\n");
402     DISP_INFO("#############################\n");
403     DISP_INFO("vid_pixel_on = 0x%x (%u)\n", lcd_timing_.vid_pixel_on,
404               lcd_timing_.vid_pixel_on);
405     DISP_INFO("vid_line_on = 0x%x (%u)\n", lcd_timing_.vid_line_on,
406               lcd_timing_.vid_line_on);
407     DISP_INFO("de_hs_addr = 0x%x (%u)\n", lcd_timing_.de_hs_addr,
408               lcd_timing_.de_hs_addr);
409     DISP_INFO("de_he_addr = 0x%x (%u)\n", lcd_timing_.de_he_addr,
410               lcd_timing_.de_he_addr);
411     DISP_INFO("de_vs_addr = 0x%x (%u)\n", lcd_timing_.de_vs_addr,
412               lcd_timing_.de_vs_addr);
413     DISP_INFO("de_ve_addr = 0x%x (%u)\n", lcd_timing_.de_ve_addr,
414               lcd_timing_.de_ve_addr);
415     DISP_INFO("hs_hs_addr = 0x%x (%u)\n", lcd_timing_.hs_hs_addr,
416               lcd_timing_.hs_hs_addr);
417     DISP_INFO("hs_he_addr = 0x%x (%u)\n", lcd_timing_.hs_he_addr,
418               lcd_timing_.hs_he_addr);
419     DISP_INFO("hs_vs_addr = 0x%x (%u)\n", lcd_timing_.hs_vs_addr,
420               lcd_timing_.hs_vs_addr);
421     DISP_INFO("hs_ve_addr = 0x%x (%u)\n", lcd_timing_.hs_ve_addr,
422               lcd_timing_.hs_ve_addr);
423     DISP_INFO("vs_hs_addr = 0x%x (%u)\n", lcd_timing_.vs_hs_addr,
424               lcd_timing_.vs_hs_addr);
425     DISP_INFO("vs_he_addr = 0x%x (%u)\n", lcd_timing_.vs_he_addr,
426               lcd_timing_.vs_he_addr);
427     DISP_INFO("vs_vs_addr = 0x%x (%u)\n", lcd_timing_.vs_vs_addr,
428               lcd_timing_.vs_vs_addr);
429     DISP_INFO("vs_ve_addr = 0x%x (%u)\n", lcd_timing_.vs_ve_addr,
430               lcd_timing_.vs_ve_addr);
431 }
432 
433 } // namespace astro_display
434