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