1 //*****************************************************************************
2 //
3 //! @file am_hal_dsi.c
4 //!
5 //! @brief Hardware abstraction for the Display Serial Interface
6 //!
7 //! @addtogroup dsi_4p DSI - Display Serial Interface
8 //! @ingroup apollo4p_hal
9 //! @{
10 //
11 //*****************************************************************************
12 
13 //*****************************************************************************
14 //
15 // Copyright (c) 2023, Ambiq Micro, Inc.
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are met:
20 //
21 // 1. Redistributions of source code must retain the above copyright notice,
22 // this list of conditions and the following disclaimer.
23 //
24 // 2. Redistributions in binary form must reproduce the above copyright
25 // notice, this list of conditions and the following disclaimer in the
26 // documentation and/or other materials provided with the distribution.
27 //
28 // 3. Neither the name of the copyright holder nor the names of its
29 // contributors may be used to endorse or promote products derived from this
30 // software without specific prior written permission.
31 //
32 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
33 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
36 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
37 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
38 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
39 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
40 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 // POSSIBILITY OF SUCH DAMAGE.
43 //
44 // This is part of revision stable-7da8bae71f of the AmbiqSuite Development Package.
45 //
46 //*****************************************************************************
47 
48 #include <stdint.h>
49 #include <stdbool.h>
50 #include "am_mcu_apollo.h"
51 
52 //*****************************************************************************
53 //
54 //! VDD18 control callback function
55 //
56 //*****************************************************************************
57 am_hal_dsi_external_vdd18_callback external_vdd18_callback;
58 
59 //*****************************************************************************
60 //
61 // Register callback function
62 //
63 //*****************************************************************************
64 uint32_t
am_hal_dsi_register_external_vdd18_callback(const am_hal_dsi_external_vdd18_callback cb)65 am_hal_dsi_register_external_vdd18_callback(const am_hal_dsi_external_vdd18_callback cb)
66 {
67     if (cb != NULL)
68     {
69         external_vdd18_callback = cb;
70     }
71     else
72     {
73         return AM_HAL_STATUS_INVALID_ARG;
74     }
75 
76     return AM_HAL_STATUS_SUCCESS;
77 }
78 
79 //*****************************************************************************
80 //
81 // Configure DSI frequency and timing
82 //
83 //*****************************************************************************
84 uint32_t
am_hal_dsi_timing(uint32_t ui32FreqTrim)85 am_hal_dsi_timing(uint32_t ui32FreqTrim)
86 {
87     uint32_t ui32FreqTrimLsb6;
88     ui32FreqTrimLsb6 = ui32FreqTrim & 0x3F;
89     //
90     // DPHY CLK/DATA timing parameters
91     //
92     if ((ui32FreqTrimLsb6 >= 0x0B) && (ui32FreqTrimLsb6 <= 0x0F))
93     {
94         DSI->DPHYPARAM_b.HSPREP = 0x04;
95         DSI->DPHYPARAM_b.HSZERO = 0x08;
96         DSI->DPHYPARAM_b.HSTRAIL = 0x05;
97         DSI->DPHYPARAM_b.HSEXIT = 0x14;
98         DSI->CLKLANETIMPARM_b.HSPREP = 0x04;
99         DSI->CLKLANETIMPARM_b.HSZERO = 0x1C;
100         DSI->CLKLANETIMPARM_b.HSTRAIL = 0x05;
101         DSI->CLKLANETIMPARM_b.HSEXIT = 0x0F;
102     }
103     else if ((ui32FreqTrimLsb6 >= 0x08) && (ui32FreqTrimLsb6 <= 0x0A))
104     {
105         DSI->DPHYPARAM_b.HSPREP = 0x03;
106         DSI->DPHYPARAM_b.HSZERO = 0x06;
107         DSI->DPHYPARAM_b.HSTRAIL = 0x04;
108         DSI->DPHYPARAM_b.HSEXIT = 0x0E;
109         DSI->CLKLANETIMPARM_b.HSPREP = 0x03;
110         DSI->CLKLANETIMPARM_b.HSZERO = 0x11;
111         DSI->CLKLANETIMPARM_b.HSTRAIL = 0x04;
112         DSI->CLKLANETIMPARM_b.HSEXIT = 0x0F;
113     }
114     else if ((ui32FreqTrimLsb6 >= 0x05) && (ui32FreqTrimLsb6 <= 0x07))
115     {
116         DSI->DPHYPARAM_b.HSPREP = 0x02;
117         DSI->DPHYPARAM_b.HSZERO = 0x04;
118         DSI->DPHYPARAM_b.HSTRAIL = 0x03;
119         DSI->DPHYPARAM_b.HSEXIT = 0x0A;
120         DSI->CLKLANETIMPARM_b.HSPREP = 0x02;
121         DSI->CLKLANETIMPARM_b.HSZERO = 0x0B;
122         DSI->CLKLANETIMPARM_b.HSTRAIL = 0x03;
123         DSI->CLKLANETIMPARM_b.HSEXIT = 0x0F;
124     }
125     else
126     {
127         return AM_HAL_STATUS_OUT_OF_RANGE;
128     }
129     //
130     // PLL settings
131     //
132     DSI->AFETRIM1 &= _VAL2FLD(DSI_AFETRIM1_AFETRIM1, ~0x0000007F);
133     DSI->AFETRIM1 |= _VAL2FLD(DSI_AFETRIM1_AFETRIM1, ui32FreqTrim);
134 
135     return AM_HAL_STATUS_SUCCESS;
136 }
137 
138 //*****************************************************************************
139 //
140 // Initialize the DSI
141 //
142 //*****************************************************************************
143 uint32_t
am_hal_dsi_para_config(uint8_t ui8LanesNum,uint8_t ui8DBIBusWidth,uint32_t ui32FreqTrim,bool bSendUlpsPattern)144 am_hal_dsi_para_config(uint8_t ui8LanesNum, uint8_t ui8DBIBusWidth, uint32_t ui32FreqTrim, bool bSendUlpsPattern)
145 {
146 
147     //
148     // ui32DSIFuncPrg_REG (DATA_WIDTH, RESERVED, FMT_VIDEO, CH_NO_CM, CH_NO_VM, DATA_LANE_CNT)
149     //                   [15:13]     [12:10]   [9:7]      [6:5]     [4:3]     [2:0]
150     //
151     uint32_t ui32DSIFuncPrg = 0;
152 
153     //
154     // check number of lanes parameters
155     //
156     switch (ui8LanesNum)
157     {
158         case 1:
159           ui32DSIFuncPrg |= _VAL2FLD(DSI_DSIFUNCPRG_DATALANES, 0x1);
160           break;
161 
162         case 2:
163           ui32DSIFuncPrg |= _VAL2FLD(DSI_DSIFUNCPRG_DATALANES, 0x2);
164           break;
165 
166         default:
167           return AM_HAL_STATUS_OUT_OF_RANGE;
168     }
169 
170     //
171     // check DBI bus width parameter
172     //
173     switch (ui8DBIBusWidth)
174     {
175         case 8:
176           ui32DSIFuncPrg |= _VAL2FLD(DSI_DSIFUNCPRG_REGNAME, 3);
177           break;
178 
179         case 9:
180           ui32DSIFuncPrg |= _VAL2FLD(DSI_DSIFUNCPRG_REGNAME, 2);
181           break;
182 
183         case 16:
184           ui32DSIFuncPrg |= _VAL2FLD(DSI_DSIFUNCPRG_REGNAME, 4); // opt1
185           break;
186 
187         default:
188           return AM_HAL_STATUS_OUT_OF_RANGE;
189     }
190 
191     DSI->RSTENBDFE = _VAL2FLD(DSI_RSTENBDFE_ENABLE, 0);
192 
193     //
194     // Add 1ms delay to avoid low contention.
195     //
196     am_hal_delay_us(1000);
197 
198     //
199     // write into DSI functional programming register
200     //
201     DSI->DSIFUNCPRG = ui32DSIFuncPrg;
202 
203     //
204     // write into HIGH SPEED RECEIVE TIMEOUT REGISTER
205     //
206     DSI->HSTXTIMEOUT = _VAL2FLD(DSI_HSTXTIMEOUT_MAXDURTOCNT, 0x00FFFFFF);
207 
208     //
209     //write into LOW POWER RECEIVE TIMEOUT REGISTER
210     //
211     DSI->LPRXTO = _VAL2FLD(DSI_LPRXTO_TOCHKRVS, 0xFF);
212 
213     //
214     // write into TURN AROUND TIMEOUT REGISTER
215     //
216     DSI->TURNARNDTO = _VAL2FLD(DSI_TURNARNDTO_TIMOUT, 0x1F);
217 
218     //
219     // write into DEVICE RESET TIMER REGISTER
220     //
221     DSI->DEVICERESETTIMER = _VAL2FLD(DSI_DEVICERESETTIMER_TIMOUT, 0xFF);
222 
223     //
224     // write into HIGH TO LOW SWITCH COUNT REGISTER
225     //
226     DSI->DATALANEHILOSWCNT = _VAL2FLD(DSI_DATALANEHILOSWCNT_DATALHLSWCNT, 0xFFFF);
227     DSI->INITCNT = _VAL2FLD(DSI_INITCNT_MSTR, 0x7d0);
228     DSI->LPBYTECLK = _VAL2FLD(DSI_LPBYTECLK_VALBYTECLK, 0x3);
229     DSI->CLKEOT = _VAL2FLD(DSI_CLKEOT_CLOCK, 1);
230     DSI->CLKEOT |= _VAL2FLD(DSI_CLKEOT_EOT, 1);
231     am_hal_dsi_timing(ui32FreqTrim);
232     DSI->AFETRIM2 = _VAL2FLD(DSI_AFETRIM2_AFETRIM2, 0x10000000);
233     DSI->AFETRIM2 |= _VAL2FLD(DSI_AFETRIM2_AFETRIM2, 0x00480000); // trim_2<22> and trim_2<19> need to be set for DSI TX in 1-lane configuration.
234     DSI->AFETRIM1 |= _VAL2FLD(DSI_AFETRIM1_AFETRIM1, 0x00002000); // trim_1<13> needs to be set
235 
236     //
237     // enable DSI TX and DPHY
238     //
239     DSI->AFETRIM3 |= _VAL2FLD(DSI_AFETRIM3_AFETRIM3, 0x00030000);
240     DSI->RSTENBDFE = _VAL2FLD(DSI_RSTENBDFE_ENABLE, 1);
241     DSI->DEVICEREADY |= _VAL2FLD(DSI_DEVICEREADY_READY, 1);
242 
243     //
244     // Wait for DPHY init
245     //
246     am_hal_delay_us(400);
247 
248     //
249     // ULPS Exit sequence
250     //
251     DSI->DEVICEREADY_b.ULPS = DSI_DEVICEREADY_ULPS_LOW_POWER;
252     am_hal_delay_us(10);
253     DSI->DEVICEREADY_b.ULPS = DSI_DEVICEREADY_ULPS_EXIT;
254     DSI->AFETRIM3 &= _VAL2FLD(DSI_AFETRIM3_AFETRIM3, ~0x00030000);
255     am_hal_delay_us(1010);
256     DSI->DEVICEREADY_b.ULPS = DSI_DEVICEREADY_ULPS_This;
257 
258     //
259     // Return the status.
260     //
261     return AM_HAL_STATUS_SUCCESS;
262 }
263 
264 //*****************************************************************************
265 //
266 // Initialize power and clock of DSI
267 //
268 //*****************************************************************************
269 uint32_t
am_hal_dsi_init(void)270 am_hal_dsi_init(void)
271 {
272     am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_PERIPH_DISPPHY);
273     DSI->RSTENBDFE = _VAL2FLD(DSI_RSTENBDFE_ENABLE, 0);
274     //DSI->DEVICEREADY = _VAL2FLD(DSI_DEVICEREADY_READY, 0);
275 
276     //
277     // vdd18 enable
278     //
279     if (external_vdd18_callback)
280     {
281         external_vdd18_callback(true);
282     }
283 
284     am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_DISPCLKSEL_DPHYPLL, NULL);
285     am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_DCCLK_ENABLE, NULL);
286     am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_PLLCLKSEL_HFRC12, NULL);
287     am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_PLLCLK_ENABLE, NULL);
288 
289     return AM_HAL_STATUS_SUCCESS;
290 }
291 
292 //*****************************************************************************
293 //
294 // Turn off power and clock of DSI
295 //
296 //*****************************************************************************
297 uint32_t
am_hal_dsi_deinit(void)298 am_hal_dsi_deinit(void)
299 {
300     am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_DISPCLKSEL_OFF, NULL);
301     am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_DCCLK_DISABLE, NULL);
302     am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_PLLCLKSEL_OFF, NULL);
303     am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_PLLCLK_DISABLE, NULL);
304 
305     //
306     // vdd18 disable
307     //
308     if (external_vdd18_callback)
309     {
310         external_vdd18_callback(false);
311     }
312 
313     am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_DISPPHY);
314 
315     return AM_HAL_STATUS_SUCCESS;
316 }
317 
318 //*****************************************************************************
319 //
320 // Enter ULPS mode
321 //
322 //*****************************************************************************
323 uint32_t
am_hal_dsi_ulps_entry(void)324 am_hal_dsi_ulps_entry(void)
325 {
326     DSI->DEVICEREADY_b.ULPS = DSI_DEVICEREADY_ULPS_LOW_POWER;
327     DSI->AFETRIM0 |= _VAL2FLD(DSI_AFETRIM0_AFETRIM0, 0x00000800); //  trim_0<11> needs to be set - contention detector disabled
328     am_hal_delay_us(10);
329     DSI->AFETRIM1 |= _VAL2FLD(DSI_AFETRIM1_AFETRIM1, 0x00000200); //  trim_1<9> needs to be set
330     DSI->AFETRIM2 |= _VAL2FLD(DSI_AFETRIM2_AFETRIM2, 0x0000001C); //  trim_2<2>, trim_2<3> & trim_2<4> need to be set
331     DSI->AFETRIM3 |= _VAL2FLD(DSI_AFETRIM3_AFETRIM3, 0x00038000); //  trim_3<15>, trim_3<16>, and trim_3<17> need to be set
332 
333     return AM_HAL_STATUS_SUCCESS;
334 }
335 
336 //*****************************************************************************
337 //
338 // Exit ULPS mode
339 //
340 //*****************************************************************************
341 uint32_t
am_hal_dsi_ulps_exit(void)342 am_hal_dsi_ulps_exit(void)
343 {
344     DSI->AFETRIM3 &= _VAL2FLD(DSI_AFETRIM3_AFETRIM3, ~0x00038000); //  trim_3<15>, trim_3<16>, and trim_3<17> need to be cleared
345     DSI->AFETRIM2 &= _VAL2FLD(DSI_AFETRIM2_AFETRIM2, ~0x0000001C); //  trim_2<2>, trim_2<3> & trim_2<4> need to be cleared
346     DSI->AFETRIM1 &= _VAL2FLD(DSI_AFETRIM1_AFETRIM1, ~0x00000200); //  trim_1<9> needs to be cleared
347     DSI->DEVICEREADY_b.ULPS = DSI_DEVICEREADY_ULPS_EXIT;
348     am_hal_delay_us(1010);
349     DSI->DEVICEREADY_b.ULPS = DSI_DEVICEREADY_ULPS_This;
350     DSI->AFETRIM0 &= _VAL2FLD(DSI_AFETRIM0_AFETRIM0, ~0x00000800); //  trim_0<11> needs to be cleared - contention detector enable
351 
352     return AM_HAL_STATUS_SUCCESS;
353 }
354 
355 //*****************************************************************************
356 //
357 // DSI napping
358 //
359 //*****************************************************************************
360 uint32_t
am_hal_dsi_napping(bool bSendUlpsPattern)361 am_hal_dsi_napping(bool bSendUlpsPattern)
362 {
363     am_hal_dsi_ulps_entry();
364     am_hal_dsi_deinit();
365 
366     return AM_HAL_STATUS_SUCCESS;
367 }
368 
369 //*****************************************************************************
370 //
371 // DSI wakeup
372 //
373 //*****************************************************************************
374 uint32_t
am_hal_dsi_wakeup(uint8_t ui8LanesNum,uint8_t ui8DBIBusWidth,uint32_t ui32FreqTrim,bool bSendUlpsPattern)375 am_hal_dsi_wakeup(uint8_t ui8LanesNum, uint8_t ui8DBIBusWidth, uint32_t ui32FreqTrim, bool bSendUlpsPattern)
376 {
377     am_hal_dsi_init();
378 
379     if ( am_hal_dsi_para_config(ui8LanesNum, ui8DBIBusWidth, ui32FreqTrim, bSendUlpsPattern) != 0 )
380     {
381         return AM_HAL_STATUS_FAIL;
382     }
383 
384     return AM_HAL_STATUS_SUCCESS;
385 }
386 
387 //*****************************************************************************
388 //
389 // DSI set return packet size (bytes)
390 //
391 //*****************************************************************************
392 uint32_t
am_hal_dsi_set_return_size(uint8_t ui8DataLen,bool bHS)393 am_hal_dsi_set_return_size(uint8_t ui8DataLen, bool bHS)
394 {
395     DSI->MAXRETPACSZE_b.COUNTVAL = ui8DataLen;
396     DSI->MAXRETPACSZE_b.HSLP = (uint32_t) (!bHS);
397 
398     return AM_HAL_STATUS_SUCCESS;
399 }
400 
401 //*****************************************************************************
402 //
403 // End Doxygen group.
404 //! @}
405 //
406 //*****************************************************************************
407