1 /*
2 * mipi_tx_hi35xx.c
3 *
4 * hi35xx mipi_tx driver implement
5 *
6 * Copyright (c) 2020-2023 Huawei Device Co., Ltd.
7 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
18
19 #include "mipi_tx_hi35xx.h"
20 #include <linux/io.h>
21 #include <linux/uaccess.h>
22 #include <linux/version.h>
23 #include "hdf_log.h"
24 #include "securec.h"
25 #include "osal_time.h"
26 #include "osal_io.h"
27 #include "osal_mem.h"
28 #include "mipi_dsi_define.h"
29 #include "mipi_dsi_core.h"
30 #include "mipi_tx_reg.h"
31 #include "mipi_tx_dev.h"
32
33 #ifdef __cplusplus
34 #if __cplusplus
35 extern "C" {
36 #endif
37 #endif /* End of #ifdef __cplusplus */
38
39 #define HDF_LOG_TAG mipi_tx_hi35xx
40 #define INT_MAX_VALUE 0x7fffffff
41
42 volatile MipiTxRegsTypeTag *g_mipiTxRegsVa = NULL;
43 unsigned int g_mipiTxIrqNum = MIPI_TX_IRQ;
44 unsigned int g_actualPhyDataRate;
45 static unsigned int g_regMapFlag;
46 /**
47 * @brief g_enCfg is the flag that the controller parameters have been set, which is independent of the high
48 * and low speed modes. The program design requires setting parameters before operating the controller,
49 * otherwise it will directly return to failure.
50 */
51 static bool g_enCfg = false;
52 /**
53 * @brief g_enHsMode is the high-speed mode flag. High speed is true, otherwise it is false.
54 */
55 static bool g_enHsMode = false;
56
WriteReg32(unsigned long * addr,unsigned int value,unsigned int mask)57 static void WriteReg32(unsigned long *addr, unsigned int value, unsigned int mask)
58 {
59 unsigned int t;
60
61 t = (unsigned int)OSAL_READL(addr);
62 t &= ~mask;
63 t |= value & mask;
64 OSAL_WRITEL(t, addr);
65 }
66
OsalIsb(void)67 static void OsalIsb(void)
68 {
69 isb();
70 }
71
OsalDsb(void)72 static void OsalDsb(void)
73 {
74 dsb();
75 }
76
OsalDmb(void)77 static void OsalDmb(void)
78 {
79 dmb();
80 }
81
HdfIsbDsbDmb(void)82 static void HdfIsbDsbDmb(void)
83 {
84 OsalIsb();
85 OsalDsb();
86 OsalDmb();
87 }
88
SetPhyReg(unsigned int addr,unsigned char value)89 static void SetPhyReg(unsigned int addr, unsigned char value)
90 {
91 HdfIsbDsbDmb();
92 g_mipiTxRegsVa->PHY_TST_CTRL1.u32 = (0x10000 + addr);
93 HdfIsbDsbDmb();
94 g_mipiTxRegsVa->PHY_TST_CTRL0.u32 = 0x2;
95 HdfIsbDsbDmb();
96 g_mipiTxRegsVa->PHY_TST_CTRL0.u32 = 0x0;
97 HdfIsbDsbDmb();
98 g_mipiTxRegsVa->PHY_TST_CTRL1.u32 = value;
99 HdfIsbDsbDmb();
100 g_mipiTxRegsVa->PHY_TST_CTRL0.u32 = 0x2;
101 HdfIsbDsbDmb();
102 g_mipiTxRegsVa->PHY_TST_CTRL0.u32 = 0x0;
103 HdfIsbDsbDmb();
104 }
105
MipiTxDrvGetPhyPllSet0(unsigned int phyDataRate)106 static unsigned char MipiTxDrvGetPhyPllSet0(unsigned int phyDataRate)
107 {
108 unsigned char pllSet0;
109
110 /* to get pllSet0, the parameters come from algorithm */
111 if (phyDataRate > 750) { /* 750: mipi clk */
112 pllSet0 = 0x0;
113 } else if (phyDataRate > 375) { /* 375: mipi clk */
114 pllSet0 = 0x8;
115 } else if (phyDataRate > 188) { /* 188: mipi clk */
116 pllSet0 = 0xa;
117 } else if (phyDataRate > 94) { /* 94: mipi clk */
118 pllSet0 = 0xc;
119 } else {
120 pllSet0 = 0xe;
121 }
122 return pllSet0;
123 }
124
MipiTxDrvGetPhyPllSet1Set5(unsigned int phyDataRate,unsigned char pllSet0,unsigned char * pllSet1,unsigned char * pllSet5)125 static void MipiTxDrvGetPhyPllSet1Set5(unsigned int phyDataRate,
126 unsigned char pllSet0,
127 unsigned char *pllSet1,
128 unsigned char *pllSet5)
129 {
130 int dataRateClk;
131 int pllRef;
132 int64_t int_multiplication;
133
134 dataRateClk = (int)(phyDataRate + MIPI_TX_REF_CLK - 1) / MIPI_TX_REF_CLK;
135
136 /* to get pllSet1 and pllSet5, the parameters come from algorithm */
137 if (pllSet0 / 2 == 4) { /* 2: pll, 4: pll sel */
138 pllRef = 2; /* 2: pll set */
139 } else if (pllSet0 / 2 == 5) { /* 2: pll, 5: pllSet5 */
140 pllRef = 4; /* 4: pll set */
141 } else if (pllSet0 / 2 == 6) { /* 2: pll, 6: pll sel */
142 pllRef = 8; /* 8: pll set */
143 } else if (pllSet0 / 2 == 7) { /* 2: pll, 7: pll sel */
144 pllRef = 16; /* 16: pll set */
145 } else {
146 pllRef = 1;
147 }
148 int_multiplication = (int64_t)(dataRateClk * pllRef);
149 if (int_multiplication > INT_MAX_VALUE) {
150 HDF_LOGE("MipiTxDrvGetPhyPllSet1Set5: exceeds the maximum value of type int32_t!");
151 return;
152 }
153 if (((dataRateClk * pllRef) % 2) != 0) { /* 2: pll */
154 *pllSet1 = 0x10;
155 *pllSet5 = (unsigned char)((dataRateClk * pllRef - 1) / 2); /* 2: pllRef sel */
156 } else {
157 *pllSet1 = 0x20;
158 *pllSet5 = (unsigned char)(dataRateClk * pllRef / 2 - 1); /* 2: pllRef sel */
159 }
160
161 return;
162 }
163
MipiTxDrvSetPhyPllSetX(unsigned int phyDataRate)164 static void MipiTxDrvSetPhyPllSetX(unsigned int phyDataRate)
165 {
166 unsigned char pllSet0;
167 unsigned char pllSet1;
168 unsigned char pllSet2;
169 #ifdef HI_FPGA
170 unsigned char pllSet3;
171 #endif
172 unsigned char pllSet4;
173 unsigned char pllSet5;
174
175 /* pllSet0 */
176 pllSet0 = MipiTxDrvGetPhyPllSet0(phyDataRate);
177 SetPhyReg(PLL_SET0, pllSet0);
178 /* pllSet1 */
179 MipiTxDrvGetPhyPllSet1Set5(phyDataRate, pllSet0, &pllSet1, &pllSet5);
180 SetPhyReg(PLL_SET1, pllSet1);
181 /* pllSet2 */
182 pllSet2 = 0x2;
183 SetPhyReg(PLL_SET2, pllSet2);
184 /* pllSet4 */
185 pllSet4 = 0x0;
186 SetPhyReg(PLL_SET4, pllSet4);
187
188 #ifdef HI_FPGA
189 pllSet3 = 0x1;
190 SetPhyReg(PLL_SET3, pllSet3);
191 #endif
192 /* pllSet5 */
193 SetPhyReg(PLL_SET5, pllSet5);
194
195 #ifdef MIPI_TX_DEBUG
196 HDF_LOGI("MipiTxDrvSetPhyPllSetX: \n==========phy pll info=======");
197 HDF_LOGI("pllSet0(0x14): 0x%x", pllSet0);
198 HDF_LOGI("pllSet1(0x15): 0x%x", pllSet1);
199 HDF_LOGI("pllSet2(0x16): 0x%x", pllSet2);
200 #ifdef HI_FPGA
201 HDF_LOGI("pllSet3(0x17): 0x%x", pllSet3);
202 #endif
203 HDF_LOGI("pllSet4(0x1e): 0x%x", pllSet4);
204 HDF_LOGI("=========================\n");
205 #endif
206 }
207
MipiTxDrvGetPhyClkPrepare(unsigned char * clkPrepare)208 static void MipiTxDrvGetPhyClkPrepare(unsigned char *clkPrepare)
209 {
210 unsigned char temp0;
211 unsigned char temp1;
212
213 temp0 = (unsigned char)((g_actualPhyDataRate * TCLK_PREPARE + ROUNDUP_VALUE) / INNER_PEROID - 1 +
214 ((g_actualPhyDataRate * PREPARE_COMPENSATE + ROUNDUP_VALUE) / INNER_PEROID) -
215 ((((g_actualPhyDataRate * TCLK_PREPARE + ROUNDUP_VALUE) / INNER_PEROID +
216 ((g_actualPhyDataRate * PREPARE_COMPENSATE + ROUNDUP_VALUE) / INNER_PEROID)) * INNER_PEROID -
217 PREPARE_COMPENSATE * g_actualPhyDataRate - TCLK_PREPARE * g_actualPhyDataRate) / INNER_PEROID));
218 if (temp0 > 0) { /* 0 is the minimum */
219 temp1 = temp0;
220 } else {
221 temp1 = 0; /* 0 is the minimum */
222 }
223
224 if (((temp1 + 1) * INNER_PEROID - PREPARE_COMPENSATE * g_actualPhyDataRate) > /* temp + 1 is next level period */
225 94 * g_actualPhyDataRate) { /* 94 is the maximum in mipi protocol */
226 if (temp0 > 0) {
227 *clkPrepare = temp0 - 1;
228 } else {
229 *clkPrepare = 255; /* set 255 will easy to found mistake */
230 HDF_LOGE("MipiTxDrvGetPhyClkPrepare: err when calc phy timing!");
231 }
232 } else {
233 if (temp0 > 0) { /* 0 is the minimum */
234 *clkPrepare = temp0;
235 } else {
236 *clkPrepare = 0; /* 0 is the minimum */
237 }
238 }
239 }
240
MipiTxDrvGetPhyDataPrepare(unsigned char * dataPrepare)241 static void MipiTxDrvGetPhyDataPrepare(unsigned char *dataPrepare)
242 {
243 unsigned char temp0;
244 unsigned char temp1;
245
246 /* DATA_THS_PREPARE */
247 temp0 = (unsigned char)((g_actualPhyDataRate * THS_PREPARE + ROUNDUP_VALUE) / INNER_PEROID - 1 +
248 ((g_actualPhyDataRate * PREPARE_COMPENSATE + ROUNDUP_VALUE) / INNER_PEROID) -
249 ((((g_actualPhyDataRate * THS_PREPARE + ROUNDUP_VALUE) / INNER_PEROID +
250 ((g_actualPhyDataRate * PREPARE_COMPENSATE + ROUNDUP_VALUE) / INNER_PEROID)) * INNER_PEROID -
251 PREPARE_COMPENSATE * g_actualPhyDataRate - THS_PREPARE * g_actualPhyDataRate) / INNER_PEROID));
252 if (temp0 > 0) {
253 temp1 = temp0;
254 } else {
255 temp1 = 0;
256 }
257
258 if ((g_actualPhyDataRate > 105) && /* bigger than 105 */
259 (((temp1 + 1) * INNER_PEROID - PREPARE_COMPENSATE * g_actualPhyDataRate) >
260 (85 * g_actualPhyDataRate + 6 * 1000))) { /* 85 + 6 * 1000 is the maximum in mipi protocol */
261 if (temp0 > 0) {
262 *dataPrepare = temp0 - 1;
263 } else {
264 *dataPrepare = 255; /* set 255 will easy to found mistake */
265 HDF_LOGE("MipiTxDrvGetPhyDataPrepare: err when calc phy timing!");
266 }
267 } else {
268 if (temp0 > 0) {
269 *dataPrepare = temp0;
270 } else {
271 *dataPrepare = 0;
272 }
273 }
274 }
275
276 /* get global operation timing parameters. */
MipiTxDrvGetPhyTimingParam(MipiTxPhyTimingParamTag * tp)277 static void MipiTxDrvGetPhyTimingParam(MipiTxPhyTimingParamTag *tp)
278 {
279 /* DATA0~3 TPRE-DELAY */
280 /* 1: compensate */
281 tp->dataTpreDelay = (unsigned char)((g_actualPhyDataRate * TPRE_DELAY + ROUNDUP_VALUE) / INNER_PEROID - 1);
282 /* CLK_TLPX */
283 tp->clkTlpx = (unsigned char)((g_actualPhyDataRate * TLPX + ROUNDUP_VALUE) /
284 INNER_PEROID - 1); /* 1 is compensate */
285 /* CLK_TCLK_PREPARE */
286 MipiTxDrvGetPhyClkPrepare(&tp->clkTclkPrepare);
287 /* CLK_TCLK_ZERO */
288 if ((g_actualPhyDataRate * TCLK_ZERO + ROUNDUP_VALUE) / INNER_PEROID > 4) { /* 4 is compensate */
289 tp->clkTclkZero = (unsigned char)((g_actualPhyDataRate * TCLK_ZERO + ROUNDUP_VALUE) / INNER_PEROID - 4);
290 } else {
291 tp->clkTclkZero = 0; /* 0 is minimum */
292 }
293 /* CLK_TCLK_TRAIL */
294 tp->clkTclkTrail = (unsigned char)((g_actualPhyDataRate * TCLK_TRAIL + ROUNDUP_VALUE) / INNER_PEROID);
295 /* DATA_TLPX */
296 tp->dataTlpx = (unsigned char)((g_actualPhyDataRate * TLPX + ROUNDUP_VALUE) /
297 INNER_PEROID - 1); /* 1 is compensate */
298 /* DATA_THS_PREPARE */
299 MipiTxDrvGetPhyDataPrepare(&tp->dataThsPrepare);
300 /* DATA_THS_ZERO */
301 if ((g_actualPhyDataRate * THS_ZERO + ROUNDUP_VALUE) / INNER_PEROID > 4) { /* 4 is compensate */
302 tp->dataThsZero = (unsigned char)((g_actualPhyDataRate * THS_ZERO + ROUNDUP_VALUE) / INNER_PEROID - 4);
303 } else {
304 tp->dataThsZero = 0; /* 0 is minimum */
305 }
306 /* DATA_THS_TRAIL */
307 tp->dataThsTrail = (unsigned char)((g_actualPhyDataRate * THS_TRAIL + ROUNDUP_VALUE) /
308 INNER_PEROID + 1); /* 1 is compensate */
309 }
310
311 /* set global operation timing parameters. */
MipiTxDrvSetPhyTimingParam(const MipiTxPhyTimingParamTag * tp)312 static void MipiTxDrvSetPhyTimingParam(const MipiTxPhyTimingParamTag *tp)
313 {
314 /* DATA0~3 TPRE-DELAY */
315 SetPhyReg(DATA0_TPRE_DELAY, tp->dataTpreDelay);
316 SetPhyReg(DATA1_TPRE_DELAY, tp->dataTpreDelay);
317 SetPhyReg(DATA2_TPRE_DELAY, tp->dataTpreDelay);
318 SetPhyReg(DATA3_TPRE_DELAY, tp->dataTpreDelay);
319
320 /* CLK_TLPX */
321 SetPhyReg(CLK_TLPX, tp->clkTlpx);
322 /* CLK_TCLK_PREPARE */
323 SetPhyReg(CLK_TCLK_PREPARE, tp->clkTclkPrepare);
324 /* CLK_TCLK_ZERO */
325 SetPhyReg(CLK_TCLK_ZERO, tp->clkTclkZero);
326 /* CLK_TCLK_TRAIL */
327 SetPhyReg(CLK_TCLK_TRAIL, tp->clkTclkTrail);
328
329 /*
330 * DATA_TLPX
331 * DATA_THS_PREPARE
332 * DATA_THS_ZERO
333 * DATA_THS_TRAIL
334 */
335 SetPhyReg(DATA0_TLPX, tp->dataTlpx);
336 SetPhyReg(DATA0_THS_PREPARE, tp->dataThsPrepare);
337 SetPhyReg(DATA0_THS_ZERO, tp->dataThsZero);
338 SetPhyReg(DATA0_THS_TRAIL, tp->dataThsTrail);
339 SetPhyReg(DATA1_TLPX, tp->dataTlpx);
340 SetPhyReg(DATA1_THS_PREPARE, tp->dataThsPrepare);
341 SetPhyReg(DATA1_THS_ZERO, tp->dataThsZero);
342 SetPhyReg(DATA1_THS_TRAIL, tp->dataThsTrail);
343 SetPhyReg(DATA2_TLPX, tp->dataTlpx);
344 SetPhyReg(DATA2_THS_PREPARE, tp->dataThsPrepare);
345 SetPhyReg(DATA2_THS_ZERO, tp->dataThsZero);
346 SetPhyReg(DATA2_THS_TRAIL, tp->dataThsTrail);
347 SetPhyReg(DATA3_TLPX, tp->dataTlpx);
348 SetPhyReg(DATA3_THS_PREPARE, tp->dataThsPrepare);
349 SetPhyReg(DATA3_THS_ZERO, tp->dataThsZero);
350 SetPhyReg(DATA3_THS_TRAIL, tp->dataThsTrail);
351
352 #ifdef MIPI_TX_DEBUG
353 HDF_LOGI("MipiTxDrvSetPhyTimingParam:\n==========phy timing parameters=======");
354 HDF_LOGI("data_tpre_delay(0x30/40/50/60): 0x%x", tp->dataTpreDelay);
355 HDF_LOGI("clk_tlpx(0x22): 0x%x", tp->clkTlpx);
356 HDF_LOGI("clk_tclk_prepare(0x23): 0x%x", tp->clkTclkPrepare);
357 HDF_LOGI("clk_tclk_zero(0x24): 0x%x", tp->clkTclkZero);
358 HDF_LOGI("clk_tclk_trail(0x25): 0x%x", tp->clkTclkTrail);
359 HDF_LOGI("data_tlpx(0x32/42/52/62): 0x%x", tp->dataTlpx);
360 HDF_LOGI("data_ths_prepare(0x33/43/53/63): 0x%x", tp->dataThsPrepare);
361 HDF_LOGI("data_ths_zero(0x34/44/54/64): 0x%x", tp->dataThsZero);
362 HDF_LOGI("data_ths_trail(0x35/45/55/65): 0x%x", tp->dataThsTrail);
363 HDF_LOGI("=========================\n");
364 #endif
365 }
366
367 /*
368 * set data lp2hs,hs2lp time
369 * set clk lp2hs,hs2lp time
370 * unit: hsclk
371 */
MipiTxDrvSetPhyHsLpSwitchTime(const MipiTxPhyTimingParamTag * tp)372 static void MipiTxDrvSetPhyHsLpSwitchTime(const MipiTxPhyTimingParamTag *tp)
373 {
374 /* data lp2hs,hs2lp time */
375 g_mipiTxRegsVa->PHY_TMR_CFG.u32 = ((tp->dataThsTrail - 1) << 16) + /* 16 set register */
376 tp->dataTpreDelay + tp->dataTlpx + tp->dataThsPrepare + tp->dataThsZero + 7; /* 7 from algorithm */
377 /* clk lp2hs,hs2lp time */
378 g_mipiTxRegsVa->PHY_TMR_LPCLK_CFG.u32 = ((31 + tp->dataThsTrail) << 16) + /* 31 from algorithm, 16 set register */
379 tp->clkTlpx + tp->clkTclkPrepare + tp->clkTclkZero + 6; /* 6 from algorithm */
380 #ifdef MIPI_TX_DEBUG
381 HDF_LOGI("MipiTxDrvSetPhyHsLpSwitchTime: PHY_TMR_CFG(0x9C): 0x%x", g_mipiTxRegsVa->PHY_TMR_CFG.u32);
382 HDF_LOGI("MipiTxDrvSetPhyHsLpSwitchTime: PHY_TMR_LPCLK_CFG(0x98): 0x%x", g_mipiTxRegsVa->PHY_TMR_LPCLK_CFG.u32);
383 #endif
384 }
385
MipiTxDrvSetPhyCfg(const ComboDevCfgTag * cfg)386 static void MipiTxDrvSetPhyCfg(const ComboDevCfgTag *cfg)
387 {
388 MipiTxPhyTimingParamTag tp = {0};
389
390 if (cfg == NULL) {
391 HDF_LOGE("MipiTxDrvSetPhyCfg: cfg is null!");
392 return;
393 }
394
395 /* set phy pll parameters setx */
396 MipiTxDrvSetPhyPllSetX(cfg->phyDataRate);
397 /* get global operation timing parameters */
398 MipiTxDrvGetPhyTimingParam(&tp);
399 /* set global operation timing parameters */
400 MipiTxDrvSetPhyTimingParam(&tp);
401 /* set hs switch to lp and lp switch to hs time */
402 MipiTxDrvSetPhyHsLpSwitchTime(&tp);
403 /* edpi_cmd_size */
404 g_mipiTxRegsVa->EDPI_CMD_SIZE.u32 = 0xF0;
405 /* phy enable */
406 g_mipiTxRegsVa->PHY_RSTZ.u32 = 0xf;
407 if (cfg->outputMode == OUTPUT_MODE_CSI) {
408 if (cfg->outputFormat == OUT_FORMAT_YUV420_8_BIT_NORMAL) {
409 g_mipiTxRegsVa->DATATYPE0.u32 = 0x10218;
410 g_mipiTxRegsVa->CSI_CTRL.u32 = 0x1111;
411 } else if (cfg->outputFormat == OUT_FORMAT_YUV422_8_BIT) {
412 g_mipiTxRegsVa->DATATYPE0.u32 = 0x1021E;
413 g_mipiTxRegsVa->CSI_CTRL.u32 = 0x1111;
414 }
415 } else {
416 if (cfg->outputFormat == OUT_FORMAT_RGB_16_BIT) {
417 g_mipiTxRegsVa->DATATYPE0.u32 = 0x111213D;
418 g_mipiTxRegsVa->CSI_CTRL.u32 = 0x10100;
419 } else if (cfg->outputFormat == OUT_FORMAT_RGB_18_BIT) {
420 g_mipiTxRegsVa->DATATYPE0.u32 = 0x111213D;
421 g_mipiTxRegsVa->CSI_CTRL.u32 = 0x10100;
422 } else if (cfg->outputFormat == OUT_FORMAT_RGB_24_BIT) {
423 g_mipiTxRegsVa->DATATYPE0.u32 = 0x111213D;
424 g_mipiTxRegsVa->CSI_CTRL.u32 = 0x10100;
425 }
426 }
427 g_mipiTxRegsVa->PHY_RSTZ.u32 = 0XF;
428 OsalMSleep(1);
429 g_mipiTxRegsVa->LPCLK_CTRL.u32 = 0x0;
430 }
431
MipiTxDrvGetDevStatus(MipiTxDevPhyTag * phyCtx)432 void MipiTxDrvGetDevStatus(MipiTxDevPhyTag *phyCtx)
433 {
434 if (phyCtx == NULL) {
435 HDF_LOGE("MipiTxDrvGetDevStatus: phyCtx is null!");
436 return;
437 }
438 phyCtx->hactDet = g_mipiTxRegsVa->HORI0_DET.bits.hact_det;
439 phyCtx->hallDet = g_mipiTxRegsVa->HORI0_DET.bits.hline_det;
440 phyCtx->hbpDet = g_mipiTxRegsVa->HORI1_DET.bits.hbp_det;
441 phyCtx->hsaDet = g_mipiTxRegsVa->HORI1_DET.bits.hsa_det;
442 phyCtx->vactDet = g_mipiTxRegsVa->VERT_DET.bits.vact_det;
443 phyCtx->vallDet = g_mipiTxRegsVa->VERT_DET.bits.vall_det;
444 phyCtx->vsaDet = g_mipiTxRegsVa->VSA_DET.bits.vsa_det;
445 }
446
SetOutputFormat(const ComboDevCfgTag * cfg)447 static void SetOutputFormat(const ComboDevCfgTag *cfg)
448 {
449 int colorCoding = 0;
450
451 if (cfg->outputMode == OUTPUT_MODE_CSI) {
452 if (cfg->outputFormat == OUT_FORMAT_YUV420_8_BIT_NORMAL) {
453 colorCoding = 0xd;
454 } else if (cfg->outputFormat == OUT_FORMAT_YUV422_8_BIT) {
455 colorCoding = 0x1;
456 }
457 } else {
458 if (cfg->outputFormat == OUT_FORMAT_RGB_16_BIT) {
459 colorCoding = 0x0;
460 } else if (cfg->outputFormat == OUT_FORMAT_RGB_18_BIT) {
461 colorCoding = 0x3;
462 } else if (cfg->outputFormat == OUT_FORMAT_RGB_24_BIT) {
463 colorCoding = 0x5;
464 }
465 }
466 g_mipiTxRegsVa->COLOR_CODING.u32 = (uint32_t)colorCoding;
467 #ifdef MIPI_TX_DEBUG
468 HDF_LOGI("SetOutputFormat: set output format: 0x%x", colorCoding);
469 #endif
470 }
471
SetVideoModeCfg(const ComboDevCfgTag * cfg)472 static void SetVideoModeCfg(const ComboDevCfgTag *cfg)
473 {
474 int videoMode;
475
476 if (cfg->videoMode == NON_BURST_MODE_SYNC_PULSES) {
477 videoMode = 0;
478 } else if (cfg->videoMode == NON_BURST_MODE_SYNC_EVENTS) {
479 videoMode = 1;
480 } else {
481 videoMode = 2; /* 2 register value */
482 }
483 if ((cfg->outputMode == OUTPUT_MODE_CSI) || (cfg->outputMode == OUTPUT_MODE_DSI_CMD)) {
484 videoMode = 2; /* 2 register value */
485 }
486 g_mipiTxRegsVa->VID_MODE_CFG.u32 = 0x3f00 + videoMode;
487 }
488
SetTimingConfig(const ComboDevCfgTag * cfg)489 static void SetTimingConfig(const ComboDevCfgTag *cfg)
490 {
491 unsigned int hsa;
492 unsigned int hbp;
493 unsigned int hline;
494
495 if (cfg->pixelClk == 0) {
496 HDF_LOGE("SetTimingConfig: cfg->pixelClk is 0, illegal!");
497 return;
498 }
499 /* 125 from algorithm */
500 hsa = g_actualPhyDataRate * cfg->syncInfo.vidHsaPixels * 125 / cfg->pixelClk;
501 /* 125 from algorithm */
502 hbp = g_actualPhyDataRate * cfg->syncInfo.vidHbpPixels * 125 / cfg->pixelClk;
503 /* 125 from algorithm */
504 hline = g_actualPhyDataRate * cfg->syncInfo.vidHlinePixels * 125 / cfg->pixelClk;
505 g_mipiTxRegsVa->VID_HSA_TIME.u32 = hsa;
506 g_mipiTxRegsVa->VID_HBP_TIME.u32 = hbp;
507 g_mipiTxRegsVa->VID_HLINE_TIME.u32 = hline;
508 g_mipiTxRegsVa->VID_VSA_LINES.u32 = cfg->syncInfo.vidVsaLines;
509 g_mipiTxRegsVa->VID_VBP_LINES.u32 = cfg->syncInfo.vidVbpLines;
510 g_mipiTxRegsVa->VID_VFP_LINES.u32 = cfg->syncInfo.vidVfpLines;
511 g_mipiTxRegsVa->VID_VACTIVE_LINES.u32 = cfg->syncInfo.vidActiveLines;
512 #ifdef MIPI_TX_DEBUG
513 HDF_LOGI("SetTimingConfig:\n==========Set Timing Config=======");
514 HDF_LOGI("VID_HSA_TIME(0x48): 0x%x", hsa);
515 HDF_LOGI("VID_HBP_TIME(0x4c): 0x%x", hbp);
516 HDF_LOGI("VID_HLINE_TIME(0x50): 0x%x", hline);
517 HDF_LOGI("VID_VSA_LINES(0x54): 0x%x", cfg->syncInfo.vidVsaLines);
518 HDF_LOGI("VID_VBP_LINES(0x58): 0x%x", cfg->syncInfo.vidVbpLines);
519 HDF_LOGI("VID_VFP_LINES(0x5c): 0x%x", cfg->syncInfo.vidVfpLines);
520 HDF_LOGI("VID_VACTIVE_LINES(0x60): 0x%x", cfg->syncInfo.vidActiveLines);
521 HDF_LOGI("=========================\n");
522 #endif
523 }
524
SetLaneConfig(const short laneId[],int len)525 static void SetLaneConfig(const short laneId[], int len)
526 {
527 uint32_t num = 0;
528 int i;
529
530 for (i = 0; i < len; i++) {
531 if (laneId[i] != -1) {
532 num++;
533 }
534 }
535 g_mipiTxRegsVa->PHY_IF_CFG.u32 = (unsigned int)(num - 1);
536 }
537
MipiTxDrvSetClkMgrCfg(void)538 static void MipiTxDrvSetClkMgrCfg(void)
539 {
540 if (g_actualPhyDataRate / 160 < 2) { /* 160 cal div, should not smaller than 2 */
541 g_mipiTxRegsVa->CLKMGR_CFG.u32 = 0x102;
542 } else {
543 g_mipiTxRegsVa->CLKMGR_CFG.u32 = 0x100 + (g_actualPhyDataRate + 159) / 160; /* 159 160 cal div */
544 }
545 }
546
MipiTxDrvSetControllerCfg(const ComboDevCfgTag * cfg)547 static void MipiTxDrvSetControllerCfg(const ComboDevCfgTag *cfg)
548 {
549 if (cfg == NULL) {
550 HDF_LOGE("MipiTxDrvSetControllerCfg: cfg is null!");
551 return;
552 }
553 /* disable input */
554 g_mipiTxRegsVa->OPERATION_MODE.u32 = 0x0;
555 /* vc_id */
556 g_mipiTxRegsVa->VCID.u32 = 0x0;
557 /* output format,color coding */
558 SetOutputFormat(cfg);
559 /* txescclk,timeout */
560 g_actualPhyDataRate = ((cfg->phyDataRate + MIPI_TX_REF_CLK - 1) / MIPI_TX_REF_CLK) * MIPI_TX_REF_CLK;
561 MipiTxDrvSetClkMgrCfg();
562 /* cmd transmission mode */
563 g_mipiTxRegsVa->CMD_MODE_CFG.u32 = 0xffffff00;
564 /* crc,ecc,eotp tran */
565 g_mipiTxRegsVa->PCKHDL_CFG.u32 = 0x1c;
566 /* gen_vcid_rx */
567 g_mipiTxRegsVa->GEN_VCID.u32 = 0x0;
568 /* mode config */
569 g_mipiTxRegsVa->MODE_CFG.u32 = 0x1;
570 /* video mode cfg */
571 SetVideoModeCfg(cfg);
572 if ((cfg->outputMode == OUTPUT_MODE_DSI_VIDEO) || (cfg->outputMode == OUTPUT_MODE_CSI)) {
573 g_mipiTxRegsVa->VID_PKT_SIZE.u32 = cfg->syncInfo.vidPktSize;
574 } else {
575 g_mipiTxRegsVa->EDPI_CMD_SIZE.u32 = cfg->syncInfo.edpiCmdSize;
576 }
577 /* num_chunks/null_size */
578 g_mipiTxRegsVa->VID_NUM_CHUNKS.u32 = 0x0;
579 g_mipiTxRegsVa->VID_NULL_SIZE.u32 = 0x0;
580 /* timing config */
581 SetTimingConfig(cfg);
582 /* invact,outvact time */
583 g_mipiTxRegsVa->LP_CMD_TIM.u32 = 0x0;
584 g_mipiTxRegsVa->PHY_TMR_CFG.u32 = 0x9002D;
585 g_mipiTxRegsVa->PHY_TMR_LPCLK_CFG.u32 = 0x29002E;
586 g_mipiTxRegsVa->EDPI_CMD_SIZE.u32 = 0xF0;
587 /* lp_wr_to_cnt */
588 g_mipiTxRegsVa->LP_WR_TO_CNT.u32 = 0x0;
589 /* bta_to_cnt */
590 g_mipiTxRegsVa->BTA_TO_CNT.u32 = 0x0;
591 /* lanes */
592 SetLaneConfig(cfg->laneId, LANE_MAX_NUM);
593 /* phy_tx requlpsclk */
594 g_mipiTxRegsVa->PHY_ULPS_CTRL.u32 = 0x0;
595 /* int msk0 */
596 g_mipiTxRegsVa->INT_MSK0.u32 = 0x0;
597 /* pwr_up unreset */
598 g_mipiTxRegsVa->PWR_UP.u32 = 0x0;
599 g_mipiTxRegsVa->PWR_UP.u32 = 0xf;
600 }
601
MipiTxWaitCmdFifoEmpty(void)602 static int MipiTxWaitCmdFifoEmpty(void)
603 {
604 U_CMD_PKT_STATUS cmdPktStatus;
605 unsigned int waitCnt;
606
607 waitCnt = 0;
608 do {
609 cmdPktStatus.u32 = g_mipiTxRegsVa->CMD_PKT_STATUS.u32;
610 waitCnt++;
611 OsalUDelay(1);
612 if (waitCnt > MIPI_TX_READ_TIMEOUT_CNT) {
613 HDF_LOGW("MipiTxWaitCmdFifoEmpty: timeout when send cmd buffer!");
614 return HDF_ERR_TIMEOUT;
615 }
616 } while (cmdPktStatus.bits.gen_cmd_empty == 0);
617 return HDF_SUCCESS;
618 }
619
MipiTxWaitWriteFifoEmpty(void)620 static int MipiTxWaitWriteFifoEmpty(void)
621 {
622 U_CMD_PKT_STATUS cmdPktStatus;
623 unsigned int waitCnt;
624
625 waitCnt = 0;
626 do {
627 cmdPktStatus.u32 = g_mipiTxRegsVa->CMD_PKT_STATUS.u32;
628 waitCnt++;
629 OsalUDelay(1);
630 if (waitCnt > MIPI_TX_READ_TIMEOUT_CNT) {
631 HDF_LOGW("MipiTxWaitWriteFifoEmpty: timeout when send data buffer!");
632 return HDF_ERR_TIMEOUT;
633 }
634 } while (cmdPktStatus.bits.gen_pld_w_empty == 0);
635 return HDF_SUCCESS;
636 }
637
MipiTxWaitWriteFifoNotFull(void)638 static int MipiTxWaitWriteFifoNotFull(void)
639 {
640 U_CMD_PKT_STATUS cmdPktStatus;
641 unsigned int waitCnt;
642
643 waitCnt = 0;
644 do {
645 cmdPktStatus.u32 = g_mipiTxRegsVa->CMD_PKT_STATUS.u32;
646 if (waitCnt > 0) {
647 OsalUDelay(1);
648 HDF_LOGW("MipiTxWaitWriteFifoNotFull: write fifo full happened wait count = %u!", waitCnt);
649 }
650 if (waitCnt > MIPI_TX_READ_TIMEOUT_CNT) {
651 HDF_LOGW("MipiTxWaitWriteFifoNotFull: timeout when wait write fifo not full buffer!");
652 return HDF_ERR_TIMEOUT;
653 }
654 waitCnt++;
655 } while (cmdPktStatus.bits.gen_pld_w_full == 1);
656 return HDF_SUCCESS;
657 }
658
659 /*
660 * set payloads data by writing register
661 * each 4 bytes in cmd corresponds to one register
662 */
MipiTxDrvSetPayloadData(const unsigned char * cmd,unsigned short cmdSize)663 static void MipiTxDrvSetPayloadData(const unsigned char *cmd, unsigned short cmdSize)
664 {
665 int32_t ret;
666 U_GEN_PLD_DATA genPldData;
667 int i;
668 int j;
669
670 genPldData.u32 = g_mipiTxRegsVa->GEN_PLD_DATA.u32;
671
672 for (i = 0; i < (cmdSize / 4); i++) { /* 4 cmd once */
673 genPldData.bits.gen_pld_b1 = cmd[i * 4]; /* 0 in 4 */
674 genPldData.bits.gen_pld_b2 = cmd[i * 4 + 1]; /* 1 in 4 */
675 genPldData.bits.gen_pld_b3 = cmd[i * 4 + 2]; /* 2 in 4 */
676 genPldData.bits.gen_pld_b4 = cmd[i * 4 + 3]; /* 3 in 4 */
677 ret = MipiTxWaitWriteFifoNotFull();
678 if (ret != HDF_SUCCESS) {
679 HDF_LOGE("MipiTxDrvSetPayloadData: [MipiTxWaitWriteFifoNotFull] fail!");
680 return;
681 }
682 g_mipiTxRegsVa->GEN_PLD_DATA.u32 = genPldData.u32;
683 }
684 j = cmdSize % 4; /* remainder of 4 */
685 if (j != 0) {
686 if (j > 0) {
687 genPldData.bits.gen_pld_b1 = cmd[i * 4]; /* 0 in 4 */
688 }
689 if (j > 1) {
690 genPldData.bits.gen_pld_b2 = cmd[i * 4 + 1]; /* 1 in 4 */
691 }
692 if (j > 2) { /* bigger than 2 */
693 genPldData.bits.gen_pld_b3 = cmd[i * 4 + 2]; /* 2 in 4 */
694 }
695 ret = MipiTxWaitWriteFifoNotFull();
696 if (ret != HDF_SUCCESS) {
697 HDF_LOGE("MipiTxDrvSetPayloadData: [MipiTxWaitWriteFifoNotFull] fail!");
698 return;
699 }
700 g_mipiTxRegsVa->GEN_PLD_DATA.u32 = genPldData.u32;
701 }
702 #ifdef MIPI_TX_DEBUG
703 HDF_LOGI("MipiTxDrvSetPayloadData: \n=====set cmd=======");
704 HDF_LOGI("GEN_PLD_DATA(0x70): 0x%x", genPldData);
705 #endif
706 }
707
LinuxCopyToKernel(void * dest,uint32_t max,const void * src,uint32_t count)708 static int32_t LinuxCopyToKernel(void *dest, uint32_t max, const void *src, uint32_t count)
709 {
710 int32_t ret;
711
712 if (access_ok(
713 #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)
714 VERIFY_READ,
715 #endif
716 src, count)) { /* user space */
717 ret = (copy_from_user(dest, src, count) != 0) ? HDF_FAILURE : HDF_SUCCESS;
718 if (ret == HDF_FAILURE) {
719 HDF_LOGE("LinuxCopyToKernel: [copy_from_user] fail!");
720 }
721 } else { /* kernel space */
722 ret = (memcpy_s(dest, max, src, count) != EOK) ? HDF_FAILURE : HDF_SUCCESS;
723 if (ret == HDF_FAILURE) {
724 HDF_LOGE("LinuxCopyToKernel: [memcpy_s] fail!");
725 }
726 }
727
728 return ret;
729 }
730
MipiTxDrvSetCmdInfo(const CmdInfoTag * cmdInfo)731 static int MipiTxDrvSetCmdInfo(const CmdInfoTag *cmdInfo)
732 {
733 int32_t ret;
734 U_GEN_HDR genHdr;
735 unsigned char *cmd = NULL;
736
737 if (cmdInfo == NULL) {
738 HDF_LOGE("MipiTxDrvSetCmdInfo: cmdInfo is null!");
739 return HDF_ERR_INVALID_OBJECT;
740 }
741 genHdr.u32 = g_mipiTxRegsVa->GEN_HDR.u32;
742 if (cmdInfo->cmd != NULL) {
743 if ((cmdInfo->cmdSize > 200) || (cmdInfo->cmdSize == 0)) { /* 200 is max cmd size */
744 HDF_LOGE("MipiTxDrvSetCmdInfo: set cmd size illegal, size =%u!", cmdInfo->cmdSize);
745 return HDF_ERR_INVALID_PARAM;
746 }
747 cmd = (unsigned char *)OsalMemCalloc(cmdInfo->cmdSize);
748 if (cmd == NULL) {
749 HDF_LOGE("MipiTxDrvSetCmdInfo: OsalMemCalloc fail,please check,need %u bytes!", cmdInfo->cmdSize);
750 return HDF_ERR_MALLOC_FAIL;
751 }
752 ret = LinuxCopyToKernel(cmd, cmdInfo->cmdSize, cmdInfo->cmd, cmdInfo->cmdSize);
753 if (ret == HDF_SUCCESS) {
754 MipiTxDrvSetPayloadData(cmd, cmdInfo->cmdSize);
755 }
756 OsalMemFree(cmd);
757 cmd = NULL;
758 if (ret != HDF_SUCCESS) {
759 HDF_LOGE("MipiTxDrvSetCmdInfo: [LinuxCopyToKernel] fail!");
760 return HDF_ERR_IO;
761 }
762 }
763 genHdr.bits.gen_dt = cmdInfo->dataType;
764 genHdr.bits.gen_wc_lsbyte = cmdInfo->cmdSize & 0xff;
765 genHdr.bits.gen_wc_msbyte = (cmdInfo->cmdSize & 0xff00) >> 8; /* height 8 bits */
766 g_mipiTxRegsVa->GEN_HDR.u32 = genHdr.u32;
767 OsalUDelay(350); /* wait 350 us transfer end */
768 ret = MipiTxWaitCmdFifoEmpty();
769 if (ret != HDF_SUCCESS) {
770 HDF_LOGE("MipiTxDrvSetCmdInfo: [MipiTxWaitCmdFifoEmpty] fail!");
771 return HDF_FAILURE;
772 }
773 ret = MipiTxWaitWriteFifoEmpty();
774 if (ret != HDF_SUCCESS) {
775 HDF_LOGE("MipiTxDrvSetCmdInfo: [MipiTxWaitWriteFifoEmpty] fail!");
776 return HDF_FAILURE;
777 }
778 return HDF_SUCCESS;
779 }
780
MipiTxWaitReadFifoNotEmpty(void)781 static int MipiTxWaitReadFifoNotEmpty(void)
782 {
783 U_INT_ST0 intSt0;
784 U_INT_ST1 intSt1;
785 unsigned int waitCnt;
786 U_CMD_PKT_STATUS cmdPktStatus;
787
788 waitCnt = 0;
789 do {
790 intSt1.u32 = g_mipiTxRegsVa->INT_ST1.u32;
791 intSt0.u32 = g_mipiTxRegsVa->INT_ST0.u32;
792 if ((intSt1.u32 & 0x3e) != 0) {
793 HDF_LOGE("MipiTxWaitReadFifoNotEmpty: err happened when read data, int_st1 = 0x%x,int_st0 = %x!",
794 intSt1.u32, intSt0.u32);
795 return HDF_FAILURE;
796 }
797 if (waitCnt > MIPI_TX_READ_TIMEOUT_CNT) {
798 HDF_LOGW("MipiTxWaitReadFifoNotEmpty: timeout when read data!");
799 return HDF_ERR_TIMEOUT;
800 }
801 waitCnt++;
802 OsalUDelay(1);
803 cmdPktStatus.u32 = g_mipiTxRegsVa->CMD_PKT_STATUS.u32;
804 } while (cmdPktStatus.bits.gen_pld_r_empty == 0x1);
805 return HDF_SUCCESS;
806 }
807
MipiTxWaitReadFifoEmpty(void)808 static int MipiTxWaitReadFifoEmpty(void)
809 {
810 U_GEN_PLD_DATA pldData;
811 U_INT_ST1 intSt1;
812 unsigned int waitCnt;
813
814 waitCnt = 0;
815 do {
816 intSt1.u32 = g_mipiTxRegsVa->INT_ST1.u32;
817 if ((intSt1.bits.gen_pld_rd_err) == 0x0) {
818 pldData.u32 = g_mipiTxRegsVa->GEN_PLD_DATA.u32;
819 }
820 waitCnt++;
821 OsalUDelay(1);
822 if (waitCnt > MIPI_TX_READ_TIMEOUT_CNT) {
823 HDF_LOGW("MipiTxWaitReadFifoEmpty: timeout when clear data buffer, the last read data is 0x%x!",
824 pldData.u32);
825 return HDF_ERR_TIMEOUT;
826 }
827 } while ((intSt1.bits.gen_pld_rd_err) == 0x0);
828 return HDF_SUCCESS;
829 }
830
MipiTxSendShortPacket(unsigned char virtualChannel,short unsigned dataType,unsigned short dataParam)831 static int MipiTxSendShortPacket(unsigned char virtualChannel,
832 short unsigned dataType, unsigned short dataParam)
833 {
834 U_GEN_HDR genHdr;
835
836 genHdr.bits.gen_vc = virtualChannel;
837 genHdr.bits.gen_dt = dataType;
838 genHdr.bits.gen_wc_lsbyte = (dataParam & 0xff);
839 genHdr.bits.gen_wc_msbyte = (dataParam & 0xff00) >> 8; /* height 8 bits */
840 g_mipiTxRegsVa->GEN_HDR.u32 = genHdr.u32;
841 if (MipiTxWaitCmdFifoEmpty() != HDF_SUCCESS) {
842 HDF_LOGE("MipiTxSendShortPacket: [MipiTxWaitCmdFifoEmpty] fail!");
843 return HDF_FAILURE;
844 }
845 return HDF_SUCCESS;
846 }
847
MipiTxGetReadFifoData(unsigned int getDataSize,unsigned char * dataBuf)848 static int MipiTxGetReadFifoData(unsigned int getDataSize, unsigned char *dataBuf)
849 {
850 U_GEN_PLD_DATA pldData;
851 unsigned int i;
852 unsigned int j;
853
854 for (i = 0; i < getDataSize / 4; i++) { /* 4byte once */
855 if (MipiTxWaitReadFifoNotEmpty() != HDF_SUCCESS) {
856 HDF_LOGE("MipiTxGetReadFifoData: [MipiTxWaitReadFifoNotEmpty] fail at first!");
857 return HDF_FAILURE;
858 }
859 pldData.u32 = g_mipiTxRegsVa->GEN_PLD_DATA.u32;
860 dataBuf[i * 4] = pldData.bits.gen_pld_b1; /* 0 in 4 */
861 dataBuf[i * 4 + 1] = pldData.bits.gen_pld_b2; /* 1 in 4 */
862 dataBuf[i * 4 + 2] = pldData.bits.gen_pld_b3; /* 2 in 4 */
863 dataBuf[i * 4 + 3] = pldData.bits.gen_pld_b4; /* 3 in 4 */
864 }
865
866 j = getDataSize % 4; /* remainder of 4 */
867
868 if (j != 0) {
869 if (MipiTxWaitReadFifoNotEmpty() != HDF_SUCCESS) {
870 HDF_LOGE("MipiTxGetReadFifoData: [MipiTxWaitReadFifoNotEmpty] fail at second!");
871 return HDF_FAILURE;
872 }
873 pldData.u32 = g_mipiTxRegsVa->GEN_PLD_DATA.u32;
874 if (j > 0) {
875 dataBuf[i * 4] = pldData.bits.gen_pld_b1; /* 0 in 4 */
876 }
877 if (j > 1) {
878 dataBuf[i * 4 + 1] = pldData.bits.gen_pld_b2; /* 1 in 4 */
879 }
880 if (j > 2) { /* bigger than 2 */
881 dataBuf[i * 4 + 2] = pldData.bits.gen_pld_b3; /* 2 in 4 */
882 }
883 }
884 return HDF_SUCCESS;
885 }
886
MipiTxReset(void)887 static void MipiTxReset(void)
888 {
889 g_mipiTxRegsVa->PWR_UP.u32 = 0x0;
890 g_mipiTxRegsVa->PHY_RSTZ.u32 = 0xd;
891 OsalUDelay(1);
892 g_mipiTxRegsVa->PWR_UP.u32 = 0x1;
893 g_mipiTxRegsVa->PHY_RSTZ.u32 = 0xf;
894 OsalUDelay(1);
895 return;
896 }
897
MipiTxDrvGetCmdInfo(GetCmdInfoTag * getCmdInfo)898 static int MipiTxDrvGetCmdInfo(GetCmdInfoTag *getCmdInfo)
899 {
900 unsigned char *dataBuf = NULL;
901
902 dataBuf = (unsigned char*)OsalMemAlloc(getCmdInfo->getDataSize);
903 if (dataBuf == NULL) {
904 HDF_LOGE("MipiTxDrvGetCmdInfo: dataBuf is null!");
905 return HDF_ERR_MALLOC_FAIL;
906 }
907 if (MipiTxWaitReadFifoEmpty() != HDF_SUCCESS) {
908 HDF_LOGE("MipiTxDrvGetCmdInfo: [MipiTxWaitReadFifoEmpty] fail!");
909 goto fail0;
910 }
911 if (MipiTxSendShortPacket(0, getCmdInfo->dataType, getCmdInfo->dataParam) != HDF_SUCCESS) {
912 HDF_LOGE("MipiTxDrvGetCmdInfo: [MipiTxSendShortPacket] fail!");
913 goto fail0;
914 }
915 if (MipiTxGetReadFifoData(getCmdInfo->getDataSize, dataBuf) != HDF_SUCCESS) {
916 /* fail will block mipi data lane, so need reset */
917 MipiTxReset();
918 HDF_LOGE("MipiTxDrvGetCmdInfo: [MipiTxGetReadFifoData] fail!");
919 goto fail0;
920 }
921 if (access_ok(
922 #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)
923 VERIFY_WRITE,
924 #endif
925 getCmdInfo->getData, getCmdInfo->getDataSize)) { /* user space */
926 if (copy_to_user(getCmdInfo->getData, dataBuf, getCmdInfo->getDataSize) != 0) {
927 HDF_LOGE("MipiTxDrvGetCmdInfo: copy_to_user fail");
928 goto fail0;
929 }
930 } else { /* kernel space */
931 if (memcpy_s(getCmdInfo->getData, getCmdInfo->getDataSize, dataBuf, getCmdInfo->getDataSize) != EOK) {
932 HDF_LOGE("MipiTxDrvGetCmdInfo: memcpy_s fail");
933 goto fail0;
934 }
935 }
936 OsalMemFree(dataBuf);
937 dataBuf = NULL;
938 return HDF_SUCCESS;
939
940 fail0:
941 OsalMemFree(dataBuf);
942 dataBuf = NULL;
943 return HDF_FAILURE;
944 }
945
MipiTxDrvEnableInput(const OutPutModeTag outputMode)946 static void MipiTxDrvEnableInput(const OutPutModeTag outputMode)
947 {
948 if ((outputMode == OUTPUT_MODE_DSI_VIDEO) || (outputMode == OUTPUT_MODE_CSI)) {
949 g_mipiTxRegsVa->MODE_CFG.u32 = 0x0;
950 }
951 if (outputMode == OUTPUT_MODE_DSI_CMD) {
952 g_mipiTxRegsVa->CMD_MODE_CFG.u32 = 0x0;
953 }
954 /* enable input */
955 g_mipiTxRegsVa->OPERATION_MODE.u32 = 0x80150000;
956 g_mipiTxRegsVa->LPCLK_CTRL.u32 = 0x1;
957 MipiTxReset();
958 g_enHsMode = true;
959 }
960
MipiTxDrvDisableInput(void)961 static void MipiTxDrvDisableInput(void)
962 {
963 /* disable input */
964 g_mipiTxRegsVa->OPERATION_MODE.u32 = 0x0;
965 g_mipiTxRegsVa->CMD_MODE_CFG.u32 = 0xffffff00;
966 /* command mode */
967 g_mipiTxRegsVa->MODE_CFG.u32 = 0x1;
968 g_mipiTxRegsVa->LPCLK_CTRL.u32 = 0x0;
969 MipiTxReset();
970 g_enHsMode = false;
971 }
972
MipiTxDrvRegInit(void)973 static int MipiTxDrvRegInit(void)
974 {
975 if (!g_mipiTxRegsVa) {
976 g_mipiTxRegsVa = (MipiTxRegsTypeTag *)OsalIoRemap(MIPI_TX_REGS_ADDR, (unsigned int)MIPI_TX_REGS_SIZE);
977 if (g_mipiTxRegsVa == NULL) {
978 HDF_LOGE("MipiTxDrvRegInit: remap mipi_tx reg addr fail!");
979 return HDF_FAILURE;
980 }
981 g_regMapFlag = 1;
982 }
983
984 return HDF_SUCCESS;
985 }
986
MipiTxDrvRegExit(void)987 static void MipiTxDrvRegExit(void)
988 {
989 if (g_regMapFlag == 1) {
990 if (g_mipiTxRegsVa != NULL) {
991 OsalIoUnmap((void *)g_mipiTxRegsVa);
992 g_mipiTxRegsVa = NULL;
993 }
994 g_regMapFlag = 0;
995 }
996 }
997
MipiTxDrvHwInit(int smooth)998 static void MipiTxDrvHwInit(int smooth)
999 {
1000 unsigned long *mipiTxCrgAddr;
1001
1002 mipiTxCrgAddr = (unsigned long *)OsalIoRemap(MIPI_TX_CRG, (unsigned long)0x4);
1003 /* mipi_tx gate clk enable */
1004 WriteReg32(mipiTxCrgAddr, 1, 0x1);
1005 /* reset */
1006 if (smooth == 0) {
1007 WriteReg32(mipiTxCrgAddr, 1 << 1, 0x1 << 1);
1008 }
1009 /* unreset */
1010 WriteReg32(mipiTxCrgAddr, 0 << 1, 0x1 << 1);
1011 /* ref clk */
1012 WriteReg32(mipiTxCrgAddr, 1 << 2, 0x1 << 2); /* 2 clk bit */
1013 OsalIoUnmap((void *)mipiTxCrgAddr);
1014 }
1015
MipiTxDrvInit(int smooth)1016 static int MipiTxDrvInit(int smooth)
1017 {
1018 int32_t ret;
1019
1020 ret = MipiTxDrvRegInit();
1021 if (ret != HDF_SUCCESS) {
1022 HDF_LOGE("MipiTxDrvInit: MipiTxDrvRegInit fail!");
1023 return HDF_FAILURE;
1024 }
1025 MipiTxDrvHwInit(smooth);
1026 return HDF_SUCCESS;
1027 }
1028
MipiTxDrvExit(void)1029 static void MipiTxDrvExit(void)
1030 {
1031 MipiTxDrvRegExit();
1032 }
1033
GetDevCfg(struct MipiDsiCntlr * cntlr)1034 static ComboDevCfgTag *GetDevCfg(struct MipiDsiCntlr *cntlr)
1035 {
1036 static ComboDevCfgTag dev;
1037 int i;
1038
1039 if (cntlr == NULL) {
1040 HDF_LOGE("GetDevCfg: cntlr is null!");
1041 return NULL;
1042 }
1043 dev.devno = cntlr->devNo;
1044 dev.outputMode = (OutPutModeTag)cntlr->cfg.mode;
1045 dev.videoMode = (VideoModeTag)cntlr->cfg.burstMode;
1046 dev.outputFormat = (OutputFormatTag)cntlr->cfg.format;
1047 dev.syncInfo.vidPktSize = cntlr->cfg.timing.xPixels;
1048 dev.syncInfo.vidHsaPixels = cntlr->cfg.timing.hsaPixels;
1049 dev.syncInfo.vidHbpPixels = cntlr->cfg.timing.hbpPixels;
1050 dev.syncInfo.vidHlinePixels = cntlr->cfg.timing.hlinePixels;
1051 dev.syncInfo.vidVsaLines = cntlr->cfg.timing.vsaLines;
1052 dev.syncInfo.vidVbpLines = cntlr->cfg.timing.vbpLines;
1053 dev.syncInfo.vidVfpLines = cntlr->cfg.timing.vfpLines;
1054 dev.syncInfo.vidActiveLines = cntlr->cfg.timing.ylines;
1055 dev.syncInfo.edpiCmdSize = cntlr->cfg.timing.edpiCmdSize;
1056 dev.phyDataRate = cntlr->cfg.phyDataRate;
1057 dev.pixelClk = cntlr->cfg.pixelClk;
1058 for (i = 0; i < LANE_MAX_NUM; i++) {
1059 dev.laneId[i] = -1; /* -1 : not use */
1060 }
1061 for (i = 0; i < cntlr->cfg.lane; i++) {
1062 dev.laneId[i] = i;
1063 }
1064 return &dev;
1065 }
1066
MipiTxCheckCombDevCfg(const ComboDevCfgTag * devCfg)1067 static int MipiTxCheckCombDevCfg(const ComboDevCfgTag *devCfg)
1068 {
1069 int i;
1070 int validLaneId[LANE_MAX_NUM] = {0, 1, 2, 3};
1071
1072 if (g_enHsMode) {
1073 HDF_LOGE("MipiTxCheckCombDevCfg: mipi_tx dev has enable!");
1074 return HDF_FAILURE;
1075 }
1076 if (devCfg->devno != 0) {
1077 HDF_LOGE("MipiTxCheckCombDevCfg: mipi_tx dev devno err!");
1078 return HDF_ERR_INVALID_PARAM;
1079 }
1080 for (i = 0; i < LANE_MAX_NUM; i++) {
1081 if ((devCfg->laneId[i] != validLaneId[i]) && (devCfg->laneId[i] != MIPI_TX_DISABLE_LANE_ID)) {
1082 HDF_LOGE("MipiTxCheckCombDevCfg: mipi_tx dev laneId %d err!", devCfg->laneId[i]);
1083 return HDF_ERR_INVALID_PARAM;
1084 }
1085 }
1086 if ((devCfg->outputMode != OUTPUT_MODE_CSI) && (devCfg->outputMode != OUTPUT_MODE_DSI_VIDEO) &&
1087 (devCfg->outputMode != OUTPUT_MODE_DSI_CMD)) {
1088 HDF_LOGE("MipiTxCheckCombDevCfg: mipi_tx dev outputMode %d err!", devCfg->outputMode);
1089 return HDF_ERR_INVALID_PARAM;
1090 }
1091 if ((devCfg->videoMode != BURST_MODE) && (devCfg->videoMode != NON_BURST_MODE_SYNC_PULSES) &&
1092 (devCfg->videoMode != NON_BURST_MODE_SYNC_EVENTS)) {
1093 HDF_LOGE("MipiTxCheckCombDevCfg: mipi_tx dev videoMode %d err!", devCfg->videoMode);
1094 return HDF_ERR_INVALID_PARAM;
1095 }
1096 if ((devCfg->outputFormat != OUT_FORMAT_RGB_16_BIT) && (devCfg->outputFormat != OUT_FORMAT_RGB_18_BIT) &&
1097 (devCfg->outputFormat != OUT_FORMAT_RGB_24_BIT) && (devCfg->outputFormat !=
1098 OUT_FORMAT_YUV420_8_BIT_NORMAL) && (devCfg->outputFormat != OUT_FORMAT_YUV420_8_BIT_LEGACY) &&
1099 (devCfg->outputFormat != OUT_FORMAT_YUV422_8_BIT)) {
1100 HDF_LOGE("MipiTxCheckCombDevCfg: mipi_tx dev outputFormat %d err!", devCfg->outputFormat);
1101 return HDF_ERR_INVALID_PARAM;
1102 }
1103
1104 return HDF_SUCCESS;
1105 }
1106
MipiTxSetComboDevCfg(const ComboDevCfgTag * devCfg)1107 static int MipiTxSetComboDevCfg(const ComboDevCfgTag *devCfg)
1108 {
1109 int32_t ret;
1110
1111 ret = MipiTxCheckCombDevCfg(devCfg);
1112 if (ret != HDF_SUCCESS) {
1113 HDF_LOGE("MipiTxSetComboDevCfg: mipi_tx check combo_dev config fail!");
1114 return ret;
1115 }
1116 /* set controller config */
1117 MipiTxDrvSetControllerCfg(devCfg);
1118 /* set phy config */
1119 MipiTxDrvSetPhyCfg(devCfg);
1120 g_enCfg = true;
1121 return ret;
1122 }
1123
Hi35xxSetCntlrCfg(struct MipiDsiCntlr * cntlr)1124 static int32_t Hi35xxSetCntlrCfg(struct MipiDsiCntlr *cntlr)
1125 {
1126 ComboDevCfgTag *dev = GetDevCfg(cntlr);
1127
1128 if (dev == NULL) {
1129 HDF_LOGE("Hi35xxSetCntlrCfg: dev is null!");
1130 return HDF_ERR_INVALID_OBJECT;
1131 }
1132 return MipiTxSetComboDevCfg(dev);
1133 }
1134
MipiTxCheckSetCmdInfo(const CmdInfoTag * cmdInfo)1135 static int MipiTxCheckSetCmdInfo(const CmdInfoTag *cmdInfo)
1136 {
1137 if (g_enHsMode) {
1138 HDF_LOGE("MipiTxCheckSetCmdInfo: mipi_tx dev has enable!");
1139 return HDF_FAILURE;
1140 }
1141
1142 if (!g_enCfg) {
1143 HDF_LOGE("MipiTxCheckSetCmdInfo: mipi_tx dev has not config!");
1144 return HDF_FAILURE;
1145 }
1146 if (cmdInfo->devno != 0) {
1147 HDF_LOGE("MipiTxCheckSetCmdInfo: mipi_tx devno %d err!", cmdInfo->devno);
1148 return HDF_ERR_INVALID_PARAM;
1149 }
1150 /* When cmd is not NULL, cmd_size means the length of cmd or it means cmd and addr */
1151 if (cmdInfo->cmd != NULL) {
1152 if (cmdInfo->cmdSize > MIPI_TX_SET_DATA_SIZE) {
1153 HDF_LOGE("MipiTxCheckSetCmdInfo: mipi_tx dev cmd_size %d err!", cmdInfo->cmdSize);
1154 return HDF_ERR_INVALID_PARAM;
1155 }
1156 }
1157 return HDF_SUCCESS;
1158 }
1159
MipiTxSetCmd(const CmdInfoTag * cmdInfo)1160 static int MipiTxSetCmd(const CmdInfoTag *cmdInfo)
1161 {
1162 int32_t ret;
1163 if (cmdInfo == NULL) {
1164 HDF_LOGE("MipiTxSetCmd: cmdInfo is null!");
1165 return HDF_ERR_INVALID_OBJECT;
1166 }
1167 ret = MipiTxCheckSetCmdInfo(cmdInfo);
1168 if (ret != HDF_SUCCESS) {
1169 HDF_LOGE("MipiTxSetCmd: mipi_tx check combo_dev config fail!");
1170 return ret;
1171 }
1172 return MipiTxDrvSetCmdInfo(cmdInfo);
1173 }
1174
Hi35xxSetCmd(struct MipiDsiCntlr * cntlr,struct DsiCmdDesc * cmd)1175 static int32_t Hi35xxSetCmd(struct MipiDsiCntlr *cntlr, struct DsiCmdDesc *cmd)
1176 {
1177 CmdInfoTag cmdInfo;
1178
1179 (void)cntlr;
1180 if (cmd == NULL) {
1181 HDF_LOGE("Hi35xxSetCmd: cmd is null!");
1182 return HDF_ERR_INVALID_OBJECT;
1183 }
1184 cmdInfo.devno = 0;
1185 if (cmd->dataLen > 2) { /* 2: use long data type */
1186 cmdInfo.cmdSize = cmd->dataLen;
1187 cmdInfo.dataType = cmd->dataType; /* 0x29: long data type */
1188 cmdInfo.cmd = cmd->payload;
1189 } else if (cmd->dataLen == 2) { /* 2: use short data type */
1190 uint16_t tmp = cmd->payload[1]; /* 3: payload */
1191 tmp = (tmp & 0x00ff) << 8; /* 0x00ff , 8: payload to high */
1192 tmp = 0xff00 & tmp;
1193 tmp = tmp | cmd->payload[0]; /* 2: reg addr */
1194 cmdInfo.cmdSize = tmp;
1195 cmdInfo.dataType = cmd->dataType; /* 0x23: short data type */
1196 cmdInfo.cmd = NULL;
1197 } else if (cmd->dataLen == 1) {
1198 cmdInfo.cmdSize = cmd->payload[0]; /* 2: reg addr */
1199 cmdInfo.dataType = cmd->dataType; /* 0x05: short data type */
1200 cmdInfo.cmd = NULL;
1201 } else {
1202 HDF_LOGE("Hi35xxSetCmd: dataLen error!");
1203 return HDF_ERR_INVALID_PARAM;
1204 }
1205 return MipiTxSetCmd(&cmdInfo);
1206 }
1207
MipiTxCheckGetCmdInfo(const GetCmdInfoTag * getCmdInfo)1208 static int MipiTxCheckGetCmdInfo(const GetCmdInfoTag *getCmdInfo)
1209 {
1210 if (g_enHsMode) {
1211 HDF_LOGE("MipiTxCheckGetCmdInfo: mipi_tx dev has enable!");
1212 return HDF_FAILURE;
1213 }
1214
1215 if (!g_enCfg) {
1216 HDF_LOGE("MipiTxCheckGetCmdInfo: mipi_tx dev has not config!");
1217 return HDF_FAILURE;
1218 }
1219 if (getCmdInfo->devno != 0) {
1220 HDF_LOGE("MipiTxCheckGetCmdInfo: mipi_tx dev devno %u err!", getCmdInfo->devno);
1221 return HDF_ERR_INVALID_PARAM;
1222 }
1223 if ((getCmdInfo->getDataSize == 0) || (getCmdInfo->getDataSize > MIPI_TX_GET_DATA_SIZE)) {
1224 HDF_LOGE("MipiTxCheckGetCmdInfo: mipi_tx dev getDataSize %hu err!", getCmdInfo->getDataSize);
1225 return HDF_ERR_INVALID_PARAM;
1226 }
1227 if (getCmdInfo->getData == NULL) {
1228 HDF_LOGE("MipiTxCheckGetCmdInfo: mipi_tx dev getData is null!");
1229 return HDF_ERR_INVALID_OBJECT;
1230 }
1231 return HDF_SUCCESS;
1232 }
1233
MipiTxGetCmd(GetCmdInfoTag * getCmdInfo)1234 static int MipiTxGetCmd(GetCmdInfoTag *getCmdInfo)
1235 {
1236 int32_t ret;
1237
1238 ret = MipiTxCheckGetCmdInfo(getCmdInfo);
1239 if (ret != HDF_SUCCESS) {
1240 HDF_LOGE("MipiTxGetCmd: [MipiTxCheckGetCmdInfo] fail!");
1241 return ret;
1242 }
1243 return MipiTxDrvGetCmdInfo(getCmdInfo);
1244 }
1245
Hi35xxGetCmd(struct MipiDsiCntlr * cntlr,struct DsiCmdDesc * cmd,uint32_t readLen,uint8_t * out)1246 static int32_t Hi35xxGetCmd(struct MipiDsiCntlr *cntlr, struct DsiCmdDesc *cmd, uint32_t readLen, uint8_t *out)
1247 {
1248 GetCmdInfoTag cmdInfo;
1249
1250 (void)cntlr;
1251 if (cmd == NULL || out == NULL) {
1252 HDF_LOGE("Hi35xxGetCmd: cmd or out is null!");
1253 return HDF_ERR_INVALID_OBJECT;
1254 }
1255 cmdInfo.devno = 0;
1256 cmdInfo.dataType = cmd->dataType;
1257 cmdInfo.dataParam = cmd->payload[0];
1258 cmdInfo.getDataSize = readLen;
1259 cmdInfo.getData = out;
1260 return MipiTxGetCmd(&cmdInfo);
1261 }
1262
Hi35xxToLp(struct MipiDsiCntlr * cntlr)1263 static void Hi35xxToLp(struct MipiDsiCntlr *cntlr)
1264 {
1265 (void)cntlr;
1266 MipiTxDrvDisableInput();
1267 }
1268
Hi35xxToHs(struct MipiDsiCntlr * cntlr)1269 static void Hi35xxToHs(struct MipiDsiCntlr *cntlr)
1270 {
1271 ComboDevCfgTag *dev = GetDevCfg(cntlr);
1272
1273 if (dev == NULL) {
1274 HDF_LOGE("Hi35xxToHs: dev is null!");
1275 return;
1276 }
1277 MipiTxDrvEnableInput(dev->outputMode);
1278 }
1279
1280 static struct MipiDsiCntlr g_mipiTx = {
1281 .devNo = 0
1282 };
1283
1284 static struct MipiDsiCntlrMethod g_method = {
1285 .setCntlrCfg = Hi35xxSetCntlrCfg,
1286 .setCmd = Hi35xxSetCmd,
1287 .getCmd = Hi35xxGetCmd,
1288 .toHs = Hi35xxToHs,
1289 .toLp = Hi35xxToLp
1290 };
1291
Hi35xxMipiTxInit(struct HdfDeviceObject * device)1292 static int32_t Hi35xxMipiTxInit(struct HdfDeviceObject *device)
1293 {
1294 int32_t ret;
1295
1296 g_mipiTx.priv = NULL;
1297 g_mipiTx.ops = &g_method;
1298 ret = MipiDsiRegisterCntlr(&g_mipiTx, device);
1299 if (ret != HDF_SUCCESS) {
1300 HDF_LOGE("Hi35xxMipiTxInit: [MipiDsiRegisterCntlr] fail!");
1301 return ret;
1302 }
1303
1304 ret = MipiTxDrvInit(0);
1305 if (ret != HDF_SUCCESS) {
1306 HDF_LOGE("Hi35xxMipiTxInit: [MipiTxDrvInit] fail.");
1307 return ret;
1308 }
1309 ret = MipiDsiDevModuleInit(g_mipiTx.devNo);
1310 if (ret != HDF_SUCCESS) {
1311 HDF_LOGE("Hi35xxMipiTxInit: [MipiDsiDevModuleInit] fail!");
1312 return ret;
1313 }
1314 HDF_LOGI("Hi35xxMipiTxInit: load mipi tx driver successfully!");
1315
1316 return ret;
1317 }
1318
Hi35xxMipiTxRelease(struct HdfDeviceObject * device)1319 static void Hi35xxMipiTxRelease(struct HdfDeviceObject *device)
1320 {
1321 struct MipiDsiCntlr *cntlr = NULL;
1322
1323 if (device == NULL) {
1324 HDF_LOGE("Hi35xxMipiTxRelease: device is null!");
1325 return;
1326 }
1327 cntlr = MipiDsiCntlrFromDevice(device);
1328 if (cntlr == NULL) {
1329 HDF_LOGE("Hi35xxMipiTxRelease: cntlr is null!");
1330 return;
1331 }
1332
1333 MipiTxDrvExit();
1334 MipiDsiDevModuleExit(cntlr->devNo);
1335 MipiDsiUnregisterCntlr(&g_mipiTx);
1336 g_mipiTx.priv = NULL;
1337 HDF_LOGI("Hi35xxMipiTxRelease: unload mipi tx driver successfully!");
1338 }
1339
1340 struct HdfDriverEntry g_mipiTxDriverEntry = {
1341 .moduleVersion = 1,
1342 .Init = Hi35xxMipiTxInit,
1343 .Release = Hi35xxMipiTxRelease,
1344 .moduleName = "HDF_MIPI_TX",
1345 };
1346 HDF_INIT(g_mipiTxDriverEntry);
1347
1348 #ifdef __cplusplus
1349 #if __cplusplus
1350 }
1351 #endif
1352 #endif /* End of #ifdef __cplusplus */
1353