fpl011_options.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. /*
  2. * Copyright : (C) 2022 Phytium Information Technology, Inc.
  3. * All Rights Reserved.
  4. *
  5. * This program is OPEN SOURCE software: you can redistribute it and/or modify it
  6. * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
  7. * either version 1.0 of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
  10. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. * See the Phytium Public License for more details.
  12. *
  13. *
  14. * FilePath: fpl011_options.c
  15. * Date: 2022-02-10 14:53:42
  16. * LastEditTime: 2022-02-18 09:06:45
  17. * Description:  This files is for uart option setting
  18. *
  19. * Modify History:
  20. * Ver   Who        Date         Changes
  21. * ----- ------     --------    --------------------------------------
  22. */
  23. /***************************** Include Files *********************************/
  24. #include "fpl011.h"
  25. #include "fpl011_hw.h"
  26. #include "ftypes.h"
  27. /************************** Variable Definitions ****************************/
  28. /************************** Constant Definitions *****************************/
  29. /**************************** Type Definitions *******************************/
  30. /*
  31. * The following data type is a map from an option to the offset in the
  32. * register to which it belongs as well as its bit mask in that register.
  33. */
  34. typedef struct
  35. {
  36. u32 option;
  37. u32 register_offset;
  38. u32 mask;
  39. } Mapping;
  40. static Mapping option_table[] =
  41. {
  42. {FPL011_OPTION_UARTEN, FPL011CR_OFFSET, FPL011CR_UARTEN},
  43. {FPL011_OPTION_RXEN, FPL011CR_OFFSET, FPL011CR_RXE},
  44. {FPL011_OPTION_TXEN, FPL011CR_OFFSET, FPL011CR_TXE},
  45. {FPL011_OPTION_FIFOEN, FPL011LCR_H_OFFSET, FPL011LCR_H_FEN},
  46. {FPL011_OPTION_RTS, FPL011CR_OFFSET, FPL011CR_RTS},
  47. {FPL011_OPTION_DTR, FPL011CR_OFFSET, FPL011CR_DTR},
  48. {FPL011_OPTION_RTSEN, FPL011CR_OFFSET, FPL011CR_RTSEN},
  49. {FPL011_OPTION_CTSEN, FPL011CR_OFFSET, FPL011CR_CTSEN},
  50. {FPL011_OPTION_TXDMAEN, FPL011DMACR_OFFSET, FPL011DMACR_TXDMAE},
  51. {FPL011_OPTION_RXDMAEN, FPL011DMACR_OFFSET, FPL011DMACR_RXDMAE}
  52. };
  53. /***************** Macros (Inline Functions) Definitions *********************/
  54. #define FUART_NUM_OPITIONS (sizeof(option_table) / sizeof(Mapping))
  55. /************************** Function Prototypes ******************************/
  56. /*****************************************************************************/
  57. /**
  58. * @name: FPl011SetOptions
  59. * @msg: Sets the options for the specified driver instance. The options are implemented as bit masks such that multiple options may be enabled or disabled simultaneously.
  60. * @param uart_p is a pointer to the uart instance.
  61. * @param options contains the options to be set which are bit masks
  62. * contained in the file FPl011_uart.h and named FUART_OPTION_*.
  63. */
  64. void FPl011SetOptions(FPl011 *uart_p, u32 options)
  65. {
  66. u32 index;
  67. u32 reg_value;
  68. FASSERT(uart_p != NULL);
  69. FASSERT(uart_p->is_ready == FT_COMPONENT_IS_READY);
  70. for (index = 0; index < FUART_NUM_OPITIONS; index++)
  71. {
  72. reg_value = FUART_READREG32(uart_p->config.base_address, option_table[index].register_offset);
  73. if ((options & option_table[index].option) != (u32)(0))
  74. {
  75. reg_value |= option_table[index].mask;
  76. }
  77. else
  78. {
  79. reg_value &= ~option_table[index].mask;
  80. }
  81. FUART_WRITEREG32(uart_p->config.base_address, option_table[index].register_offset, reg_value);
  82. }
  83. }
  84. /**
  85. * @name: FPl011SetSpecificOptions
  86. * @msg: Sets the options for the specified driver instance.
  87. * @param {FPl011} *uart_p is a pointer to the uart instance.
  88. * @param {u32} options contains the options to be set which are bit masks
  89. * contained in the file FPl011_uart.h and named FUART_OPTION_*.
  90. */
  91. void FPl011SetSpecificOptions(FPl011 *uart_p, u32 options)
  92. {
  93. u32 index;
  94. u32 reg_value;
  95. FASSERT(uart_p != NULL);
  96. for (index = 0; index < FUART_NUM_OPITIONS; index++)
  97. {
  98. if ((options & option_table[index].option) == (u32)(0))
  99. continue;
  100. reg_value = FUART_READREG32(uart_p->config.base_address, option_table[index].register_offset);
  101. /* set specific options */
  102. reg_value |= option_table[index].mask;
  103. FUART_WRITEREG32(uart_p->config.base_address, option_table[index].register_offset, reg_value);
  104. }
  105. }
  106. /**
  107. * @name: FPl011SetSpecificOptions
  108. * @msg: Clear the options for the specified driver instance.
  109. * @param uart_p is a pointer to the uart instance.
  110. * @param options contains the options to be set which are bit masks
  111. * contained in the file FPl011_uart.h and named FUART_OPTION_*.
  112. */
  113. void FPl011ClearSpecificOptions(FPl011 *uart_p, u32 options)
  114. {
  115. u32 index;
  116. u32 reg_value;
  117. FASSERT(uart_p != NULL);
  118. for (index = 0; index < FUART_NUM_OPITIONS; index++)
  119. {
  120. if ((options & option_table[index].option) == (u32)(0))
  121. continue;
  122. reg_value = FUART_READREG32(uart_p->config.base_address, option_table[index].register_offset);
  123. /* remove specific options */
  124. reg_value &= ~option_table[index].mask;
  125. FUART_WRITEREG32(uart_p->config.base_address, option_table[index].register_offset, reg_value);
  126. }
  127. }
  128. /**
  129. * @name: FPl011SetDataFormat
  130. * @msg: Sets the data format for the specified UART.
  131. * @param uart_p is a pointer to the uart instance.
  132. * @param format_p is a pointer to a format structure that will
  133. * contain the data format after this call completes.
  134. * @return
  135. * FT_SUCCESS if everything configured as expected
  136. * FPL011_ERROR_PARAM if one of the parameters was not valid.
  137. */
  138. FError FPl011SetDataFormat(FPl011 *uart_p, FPl011Format *format_p)
  139. {
  140. FError ret ;
  141. u32 line_ctrl_reg ;
  142. FPl011Config *config_p;
  143. FASSERT(uart_p != NULL);
  144. FASSERT(uart_p->is_ready == FT_COMPONENT_IS_READY);
  145. FASSERT(format_p != NULL) ;
  146. config_p = &uart_p->config;
  147. if ((format_p->data_bits > ((u32)(FPL011_FORMAT_WORDLENGTH_8BIT))) ||
  148. (format_p->parity > ((u32)(FPL011_FORMAT_PARITY_MASK))) ||
  149. (format_p->stopbits > ((u32)(FPL011_FORMAT_PARITY_MASK)))
  150. )
  151. {
  152. return FPL011_ERROR_PARAM ;
  153. }
  154. else
  155. {
  156. /*
  157. * Try to set the baud rate and if it's not successful then
  158. * don't continue altering the data format, this is done
  159. * first to avoid the format from being altered when an
  160. * error occurs
  161. */
  162. ret = FPl011SetBaudRate(uart_p, format_p->baudrate) ;
  163. if (ret != FT_SUCCESS)
  164. {
  165. }
  166. else
  167. {
  168. line_ctrl_reg = FUART_READREG32(config_p->base_address, FPL011LCR_H_OFFSET);
  169. /*
  170. * Set the length of data (8,7,6) by first clearing
  171. * out the bits that control it in the register,
  172. * then set the length in the register
  173. */
  174. line_ctrl_reg &= ~(u32)FPL011LCR_H_WLEN ;
  175. line_ctrl_reg |= (format_p->data_bits <<
  176. FPL011LCR_H_WLEN_SHIFT);
  177. /*
  178. * Set the number of stop bits in the mode register by
  179. * first clearing out the bits that control it in the
  180. * register, then set the number of stop bits in the
  181. * register.
  182. */
  183. line_ctrl_reg &= ~FPL011LCR_H_STP_MASK;
  184. line_ctrl_reg |= (format_p->stopbits <<
  185. FPL011LCR_H_STP_SHIFT);
  186. /*
  187. * Set the parity by first clearing out the bits that
  188. * control it in the register, then set the bits in
  189. * the register, the default is no parity after
  190. * clearing the register bits
  191. */
  192. line_ctrl_reg &= ~FPL011LCR_H_PARITY_MASK;
  193. line_ctrl_reg |= ((format_p->parity &
  194. FPL011_FORMAT_EN_PARITY) <<
  195. FPL011LCR_H_PARITY_SHIFT);
  196. /* Even/Odd parity set */
  197. line_ctrl_reg |= ((format_p->parity &
  198. FPL011_FORMAT_EVEN_PARITY) <<
  199. FPL011_FORMAT_EVEN_PARITY_SHIFT);
  200. /* Stick parity enable/disable */
  201. line_ctrl_reg |= ((format_p->parity &
  202. FPL011_FORMAT_EN_STICK_PARITY) <<
  203. FPL011_FORMAT_EN_STICK_PARITY_SHIFT);
  204. /* Update the Line control register */
  205. FUART_WRITEREG32(config_p->base_address, FPL011LCR_H_OFFSET, line_ctrl_reg) ;
  206. return FT_SUCCESS ;
  207. }
  208. }
  209. return ret ;
  210. }
  211. /**
  212. * @name: FPl011GetDataFormat
  213. * @msg: Gets the data format for the specified UART.
  214. * @param uart_p is a pointer to the uart instance.
  215. * @param format_p is a pointer to a format structure that will
  216. * contain the data format after this call completes.
  217. */
  218. void FPl011GetDataFormat(FPl011 *uart_p, FPl011Format *format_p)
  219. {
  220. u32 line_ctrl_reg ;
  221. FPl011Config *config_p;
  222. /* Assert validates the input arguments */
  223. FASSERT(uart_p != NULL);
  224. FASSERT(uart_p->is_ready == FT_COMPONENT_IS_READY);
  225. FASSERT(format_p != NULL) ;
  226. config_p = &uart_p->config;
  227. /*
  228. * Get the baud rate from the instance, this is not retrieved from
  229. * the hardware because it is only kept as a divisor such that it
  230. * is more difficult to get back to the baud rate
  231. */
  232. format_p->baudrate = uart_p->config.baudrate ;
  233. line_ctrl_reg = FUART_READREG32(config_p->base_address, FPL011LCR_H_OFFSET);
  234. /* Get the length of data (8,7,6,5) */
  235. format_p->data_bits = ((line_ctrl_reg & FPL011LCR_H_WLEN) >> FPL011LCR_H_WLEN_SHIFT) ;
  236. /* Get the number of stop bits */
  237. format_p->stopbits = (u8)((line_ctrl_reg & FPL011LCR_H_STP_MASK) >> FPL011LCR_H_STP_SHIFT) ;
  238. /* Determine what parity is */
  239. format_p->parity = (u32)((line_ctrl_reg & (u32)FPL011LCR_H_PARITY_MASK) >> FPL011LCR_H_PARITY_SHIFT) ;
  240. }
  241. /**
  242. * @name: FPl011SetTxFifoThreadHold
  243. * @msg: This functions sets the Tx FIFO trigger level to the 'TriggerLevel'
  244. * argument.
  245. * @param uart_p is a pointer to the uart instance.
  246. * @param trigger_level contains the trigger level to set. This is a value
  247. * from 0-32 (FPL011IFLS_TXIFLSEL_1_8 - FPL011IFLS_TXIFLSEL_7_8)
  248. */
  249. void FPl011SetTxFifoThreadHold(FPl011 *uart_p, u8 trigger_level)
  250. {
  251. u32 fifo_trig_reg;
  252. FPl011Config *config_p;
  253. FASSERT(uart_p != NULL);
  254. FASSERT(trigger_level <= (u8)FPL011IFLS_TXIFLSEL_MASK) ;
  255. FASSERT(uart_p->is_ready == FT_COMPONENT_IS_READY);
  256. config_p = &uart_p->config;
  257. trigger_level = trigger_level & (u8)FPL011IFLS_TXIFLSEL_MASK;
  258. fifo_trig_reg = FUART_READREG32(config_p->base_address,
  259. FPL011IFLS_OFFSET);
  260. fifo_trig_reg &= ~(FPL011IFLS_TXIFLSEL_MASK | FPL011IFLS_RXIFLSEL_MASK);
  261. fifo_trig_reg |= (u32)trigger_level;
  262. /*
  263. * Write the new value for the FIFO control register to it such that
  264. * the threshold is changed
  265. */
  266. FUART_WRITEREG32(config_p->base_address,
  267. FPL011IFLS_OFFSET, fifo_trig_reg);
  268. }
  269. /**
  270. * @name: FPl011SetRxFifoThreadhold
  271. * @msg: This functions sets the Rx FIFO trigger level to the 'TriggerLevel'
  272. * argument.
  273. * @param uart_p is a pointer to the uart instance.
  274. * @param trigger_level contains the trigger level to set. This is a value
  275. * from 0-32 (FPL011IFLS_RXIFLSEL_1_8 - FPL011IFLS_RXIFLSEL_7_8)
  276. */
  277. void FPl011SetRxFifoThreadhold(FPl011 *uart_p, u8 trigger_level)
  278. {
  279. u32 fifo_trig_reg;
  280. FPl011Config *config_p;
  281. FASSERT(uart_p != NULL);
  282. FASSERT(trigger_level <= (u8)FPL011IFLS_RXIFLSEL_MASK) ;
  283. FASSERT(uart_p->is_ready == FT_COMPONENT_IS_READY);
  284. config_p = &uart_p->config;
  285. trigger_level = trigger_level & (u8)FPL011IFLS_RXIFLSEL_MASK;
  286. fifo_trig_reg = FUART_READREG32(config_p->base_address,
  287. FPL011IFLS_OFFSET);
  288. fifo_trig_reg &= ~FPL011IFLS_RXIFLSEL_MASK;
  289. fifo_trig_reg |= (u32)trigger_level ;
  290. /*
  291. * Write the new value for the FIFO control register to it such that
  292. * the threshold is changed
  293. */
  294. FUART_WRITEREG32(config_p->base_address,
  295. FPL011IFLS_OFFSET, fifo_trig_reg);
  296. }
  297. /**
  298. * @name: FPl011SetBaudRate
  299. * @msg: Sets the baud rate for the device.
  300. * @param uart_p is a pointer to the FPl011 instance
  301. * @param BaudRate to be set
  302. * @return
  303. * FT_SUCCESS if everything configured as expected
  304. * FPL011_ERROR_PARAM if the requested rate is not available
  305. * because there was too much error
  306. */
  307. FError FPl011SetBaudRate(FPl011 *uart_p, u32 baudrate)
  308. {
  309. u32 temp;
  310. u32 divider;
  311. u32 remainder;
  312. u32 fraction;
  313. FASSERT(NULL != uart_p);
  314. if ((baudrate * 2) > uart_p->config.ref_clock_hz)
  315. {
  316. return FPL011_ERROR_PARAM;
  317. }
  318. /* calculate baud rate divisor */
  319. temp = 16 * baudrate;
  320. divider = uart_p->config.ref_clock_hz / temp;
  321. remainder = uart_p->config.ref_clock_hz % temp;
  322. temp = (128 * remainder) / temp;
  323. fraction = temp / 2;
  324. if (0 != (temp & 1))
  325. {
  326. fraction++;
  327. }
  328. FPl011ClearSpecificOptions(uart_p, FPL011_OPTION_RXEN | FPL011_OPTION_TXEN);
  329. /* set baud register */
  330. FUART_WRITEREG32(uart_p->config.base_address, FPL011IBRD_OFFSET, divider);
  331. FUART_WRITEREG32(uart_p->config.base_address, FPL011FBRD_OFFSET, fraction);
  332. FPl011SetSpecificOptions(uart_p, FPL011_OPTION_RXEN | FPL011_OPTION_TXEN);
  333. uart_p->config.baudrate = baudrate;
  334. return FT_SUCCESS;
  335. }
  336. /**
  337. * @name: FPl011ProgramCtlReg
  338. * @msg: This function reprograms the control register according to the following
  339. * sequence mentioned in the TRM
  340. * @param uart_p is a pointer to the FPl011 instance
  341. * @param ctrl_reg value to be written
  342. */
  343. void FPl011ProgramCtlReg(FPl011 *uart_p, u32 ctrl_reg)
  344. {
  345. u32 line_ctrl_reg;
  346. u32 temp_ctrl_reg;
  347. u32 isbusy;
  348. u32 addr = uart_p->config.base_address;
  349. FASSERT(uart_p);
  350. /*
  351. * Check is TX completed. If Uart is disabled in the middle, cannot
  352. * recover. So, keep this check before disable.
  353. */
  354. isbusy = FUART_ISTRANSMITBUSY(addr);
  355. while (isbusy == (u32)TRUE)
  356. {
  357. isbusy = (u32)FUART_ISTRANSMITBUSY(addr);
  358. }
  359. /* Disable UART */
  360. temp_ctrl_reg = FUART_READREG32(addr, FPL011CR_OFFSET);
  361. temp_ctrl_reg &= (~FPL011CR_UARTEN);
  362. FUART_WRITEREG32(addr, FPL011CR_OFFSET, temp_ctrl_reg);
  363. /*
  364. * Flush the transmit FIFO by setting the FEN bit to 0 in the
  365. * Line Control Register
  366. */
  367. line_ctrl_reg = FUART_READREG32(addr, FPL011LCR_H_OFFSET);
  368. line_ctrl_reg &= ~FPL011LCR_H_FEN;
  369. FUART_WRITEREG32(addr, FPL011LCR_H_OFFSET, line_ctrl_reg);
  370. /* Setup the Control Register with the passed argument.*/
  371. FUART_WRITEREG32(addr, FPL011CR_OFFSET, ctrl_reg);
  372. /* By default, driver works in FIFO mode, so set FEN as it is
  373. * cleared above
  374. */
  375. line_ctrl_reg |= FPL011LCR_H_FEN;
  376. FUART_WRITEREG32(addr, FPL011LCR_H_OFFSET, line_ctrl_reg);
  377. /* Enable UART */
  378. temp_ctrl_reg = FUART_READREG32(addr, FPL011CR_OFFSET);
  379. temp_ctrl_reg |= FPL011CR_UARTEN;
  380. FUART_WRITEREG32(addr, FPL011CR_OFFSET, temp_ctrl_reg);
  381. }
  382. /**
  383. * @name: FPl011SetOperMode
  384. * @msg: This function sets the operational mode of the UART. The UART can operate
  385. * in one of four modes: Normal, Local Loopback.
  386. * @param uart_p is a pointer to the FPl011 instance.
  387. * @param operation_mode is the mode of the UART.
  388. */
  389. void FPl011SetOperMode(FPl011 *uart_p, u8 operation_mode)
  390. {
  391. u32 ctrl_reg;
  392. FPl011Config *config_p;
  393. FASSERT(uart_p != NULL);
  394. FASSERT(operation_mode <= (u8)FPL011_OPER_MODE_LOCAL_LOOP) ;
  395. FASSERT(uart_p->is_ready == FT_COMPONENT_IS_READY);
  396. config_p = &uart_p->config;
  397. ctrl_reg = FUART_READREG32(config_p->base_address, FPL011CR_OFFSET) ;
  398. /* Set the correct value by masking the bits, then ORing the const. */
  399. ctrl_reg &= ~(u32)FPL011CR_LBE;
  400. switch (operation_mode)
  401. {
  402. case FPL011_OPER_MODE_NORMAL:
  403. ctrl_reg |= FPL011CR_MODE_NORMAL;
  404. break;
  405. case FPL011_OPER_MODE_LOCAL_LOOP:
  406. ctrl_reg |= FPL011CR_LBE;
  407. break;
  408. default:
  409. break;
  410. }
  411. /* Setup the Control Register with the passed argument.*/
  412. FPl011ProgramCtlReg(uart_p, ctrl_reg);
  413. }