blob: c92a34f1f25c57620fc8f5e9bda004de0043906e [file] [log] [blame]
Deepa Dinamani9965d1e2012-12-14 13:56:13 -08001/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
2 *
Ajay Dudanib01e5062011-12-03 23:23:42 -08003 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
Deepa Dinamani9965d1e2012-12-14 13:56:13 -08006 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
Ajay Dudanib01e5062011-12-03 23:23:42 -080015 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <string.h>
30#include <stdlib.h>
31#include <debug.h>
Figo Wange3594e72014-03-31 15:50:37 +080032#include <kernel/thread.h>
Ajay Dudanib01e5062011-12-03 23:23:42 -080033#include <reg.h>
34#include <sys/types.h>
35#include <platform/iomap.h>
36#include <platform/irqs.h>
37#include <platform/interrupts.h>
38#include <platform/clock.h>
39#include <platform/gpio.h>
40#include <uart_dm.h>
41#include <gsbi.h>
42
43#ifndef NULL
44#define NULL 0
45#endif
46
Ajay Dudanib01e5062011-12-03 23:23:42 -080047
48static int uart_init_flag = 0;
49
50/* Note:
51 * This is a basic implementation of UART_DM protocol. More focus has been
52 * given on simplicity than efficiency. Few of the things to be noted are:
53 * - RX path may not be suitable for multi-threaded scenaraio because of the
54 * use of static variables. TX path shouldn't have any problem though. If
55 * multi-threaded support is required, a simple data-structure can
56 * be maintained for each thread.
57 * - Right now we are using polling method than interrupt based.
58 * - We are using legacy UART protocol without Data Mover.
59 * - Not all interrupts and error events are handled.
60 * - While waiting Watchdog hasn't been taken into consideration.
61 */
62
Deepa Dinamani9965d1e2012-12-14 13:56:13 -080063#define NON_PRINTABLE_ASCII_CHAR 128
64
65static uint8_t pack_chars_into_words(uint8_t *buffer, uint8_t cnt, uint32_t *word)
66{
67 uint8_t num_chars_writtten = 0;
68
69 *word = 0;
70
71 for(int j=0; j < cnt; j++)
72 {
73 if (buffer[num_chars_writtten] == '\n')
74 {
75 /* replace '\n' by the NON_PRINTABLE_ASCII_CHAR and print '\r'.
76 * While printing the NON_PRINTABLE_ASCII_CHAR, we will print '\n'.
77 * Thus successfully replacing '\n' by '\r' '\n'.
78 */
79 *word |= ('\r' & 0xff) << (j * 8);
80 buffer[num_chars_writtten] = NON_PRINTABLE_ASCII_CHAR;
81 }
82 else
83 {
84 if (buffer[num_chars_writtten] == NON_PRINTABLE_ASCII_CHAR)
85 {
86 buffer[num_chars_writtten] = '\n';
87 }
88
89 *word |= (buffer[num_chars_writtten] & 0xff) << (j * 8);
90
91 num_chars_writtten++;
92 }
93 }
94
95 return num_chars_writtten;
96}
Ajay Dudanib01e5062011-12-03 23:23:42 -080097
98/* Static Function Prototype Declarations */
Deepa Dinamani9965d1e2012-12-14 13:56:13 -080099static unsigned int msm_boot_uart_calculate_num_chars_to_write(char *data_in,
100 uint32_t *num_of_chars);
Amol Jadia63aaff2012-02-01 15:51:50 -0800101static unsigned int msm_boot_uart_dm_init(uint32_t base);
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700102static unsigned int msm_boot_uart_dm_read(uint32_t base,
103 unsigned int *data, int wait);
Amol Jadia63aaff2012-02-01 15:51:50 -0800104static unsigned int msm_boot_uart_dm_write(uint32_t base, char *data,
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700105 unsigned int num_of_chars);
Amol Jadia63aaff2012-02-01 15:51:50 -0800106static unsigned int msm_boot_uart_dm_init_rx_transfer(uint32_t base);
107static unsigned int msm_boot_uart_dm_reset(uint32_t base);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800108
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700109/* Keep track of uart block vs port mapping.
Ajay Dudanib01e5062011-12-03 23:23:42 -0800110 */
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700111static uint32_t port_lookup[4];
Ajay Dudanib01e5062011-12-03 23:23:42 -0800112
113/* Extern functions */
114void udelay(unsigned usecs);
115
116/*
Deepa Dinamani9965d1e2012-12-14 13:56:13 -0800117 * Helper function to keep track of Line Feed char "\n" with
Ajay Dudanib01e5062011-12-03 23:23:42 -0800118 * Carriage Return "\r\n".
Ajay Dudanib01e5062011-12-03 23:23:42 -0800119 */
120static unsigned int
Deepa Dinamani9965d1e2012-12-14 13:56:13 -0800121msm_boot_uart_calculate_num_chars_to_write(char *data_in,
122 uint32_t *num_of_chars)
Ajay Dudanib01e5062011-12-03 23:23:42 -0800123{
124 int i = 0, j = 0;
125
Deepa Dinamani9965d1e2012-12-14 13:56:13 -0800126 if ((data_in == NULL) || (*num_of_chars < 0)) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800127 return MSM_BOOT_UART_DM_E_INVAL;
128 }
129
Deepa Dinamani9965d1e2012-12-14 13:56:13 -0800130 for (i = 0, j = 0; i < *num_of_chars; i++, j++) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800131 if (data_in[i] == '\n') {
Deepa Dinamani9965d1e2012-12-14 13:56:13 -0800132 j++;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800133 }
134
Ajay Dudanib01e5062011-12-03 23:23:42 -0800135 }
136
Deepa Dinamani9965d1e2012-12-14 13:56:13 -0800137 *num_of_chars = j;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800138
139 return MSM_BOOT_UART_DM_E_SUCCESS;
140}
141
142/*
Ajay Dudanib01e5062011-12-03 23:23:42 -0800143 * Reset the UART
144 */
Amol Jadia63aaff2012-02-01 15:51:50 -0800145static unsigned int msm_boot_uart_dm_reset(uint32_t base)
Ajay Dudanib01e5062011-12-03 23:23:42 -0800146{
Amol Jadia63aaff2012-02-01 15:51:50 -0800147 writel(MSM_BOOT_UART_DM_CMD_RESET_RX, MSM_BOOT_UART_DM_CR(base));
148 writel(MSM_BOOT_UART_DM_CMD_RESET_TX, MSM_BOOT_UART_DM_CR(base));
149 writel(MSM_BOOT_UART_DM_CMD_RESET_ERR_STAT, MSM_BOOT_UART_DM_CR(base));
150 writel(MSM_BOOT_UART_DM_CMD_RES_TX_ERR, MSM_BOOT_UART_DM_CR(base));
151 writel(MSM_BOOT_UART_DM_CMD_RES_STALE_INT, MSM_BOOT_UART_DM_CR(base));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800152
153 return MSM_BOOT_UART_DM_E_SUCCESS;
154}
155
156/*
157 * Initialize UART_DM - configure clock and required registers.
158 */
Amol Jadia63aaff2012-02-01 15:51:50 -0800159static unsigned int msm_boot_uart_dm_init(uint32_t uart_dm_base)
Ajay Dudanib01e5062011-12-03 23:23:42 -0800160{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800161 /* Configure UART mode registers MR1 and MR2 */
162 /* Hardware flow control isn't supported */
Amol Jadia63aaff2012-02-01 15:51:50 -0800163 writel(0x0, MSM_BOOT_UART_DM_MR1(uart_dm_base));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800164
165 /* 8-N-1 configuration: 8 data bits - No parity - 1 stop bit */
Amol Jadia63aaff2012-02-01 15:51:50 -0800166 writel(MSM_BOOT_UART_DM_8_N_1_MODE, MSM_BOOT_UART_DM_MR2(uart_dm_base));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800167
168 /* Configure Interrupt Mask register IMR */
Amol Jadia63aaff2012-02-01 15:51:50 -0800169 writel(MSM_BOOT_UART_DM_IMR_ENABLED, MSM_BOOT_UART_DM_IMR(uart_dm_base));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800170
171 /* Configure Tx and Rx watermarks configuration registers */
172 /* TX watermark value is set to 0 - interrupt is generated when
173 * FIFO level is less than or equal to 0 */
Amol Jadia63aaff2012-02-01 15:51:50 -0800174 writel(MSM_BOOT_UART_DM_TFW_VALUE, MSM_BOOT_UART_DM_TFWR(uart_dm_base));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800175
176 /* RX watermark value */
Amol Jadia63aaff2012-02-01 15:51:50 -0800177 writel(MSM_BOOT_UART_DM_RFW_VALUE, MSM_BOOT_UART_DM_RFWR(uart_dm_base));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800178
179 /* Configure Interrupt Programming Register */
180 /* Set initial Stale timeout value */
Amol Jadia63aaff2012-02-01 15:51:50 -0800181 writel(MSM_BOOT_UART_DM_STALE_TIMEOUT_LSB, MSM_BOOT_UART_DM_IPR(uart_dm_base));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800182
183 /* Configure IRDA if required */
184 /* Disabling IRDA mode */
Amol Jadia63aaff2012-02-01 15:51:50 -0800185 writel(0x0, MSM_BOOT_UART_DM_IRDA(uart_dm_base));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800186
187 /* Configure and enable sim interface if required */
188
189 /* Configure hunt character value in HCR register */
190 /* Keep it in reset state */
Amol Jadia63aaff2012-02-01 15:51:50 -0800191 writel(0x0, MSM_BOOT_UART_DM_HCR(uart_dm_base));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800192
193 /* Configure Rx FIFO base address */
194 /* Both TX/RX shares same SRAM and default is half-n-half.
195 * Sticking with default value now.
196 * As such RAM size is (2^RAM_ADDR_WIDTH, 32-bit entries).
197 * We have found RAM_ADDR_WIDTH = 0x7f */
198
199 /* Issue soft reset command */
Amol Jadia63aaff2012-02-01 15:51:50 -0800200 msm_boot_uart_dm_reset(uart_dm_base);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800201
202 /* Enable/Disable Rx/Tx DM interfaces */
203 /* Data Mover not currently utilized. */
Amol Jadia63aaff2012-02-01 15:51:50 -0800204 writel(0x0, MSM_BOOT_UART_DM_DMEN(uart_dm_base));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800205
206 /* Enable transmitter and receiver */
Amol Jadia63aaff2012-02-01 15:51:50 -0800207 writel(MSM_BOOT_UART_DM_CR_RX_ENABLE, MSM_BOOT_UART_DM_CR(uart_dm_base));
208 writel(MSM_BOOT_UART_DM_CR_TX_ENABLE, MSM_BOOT_UART_DM_CR(uart_dm_base));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800209
210 /* Initialize Receive Path */
Amol Jadia63aaff2012-02-01 15:51:50 -0800211 msm_boot_uart_dm_init_rx_transfer(uart_dm_base);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800212
213 return MSM_BOOT_UART_DM_E_SUCCESS;
214}
215
216/*
217 * Initialize Receive Path
218 */
Amol Jadia63aaff2012-02-01 15:51:50 -0800219static unsigned int msm_boot_uart_dm_init_rx_transfer(uint32_t uart_dm_base)
Ajay Dudanib01e5062011-12-03 23:23:42 -0800220{
Amol Jadia63aaff2012-02-01 15:51:50 -0800221 writel(MSM_BOOT_UART_DM_GCMD_DIS_STALE_EVT, MSM_BOOT_UART_DM_CR(uart_dm_base));
222 writel(MSM_BOOT_UART_DM_CMD_RES_STALE_INT, MSM_BOOT_UART_DM_CR(uart_dm_base));
223 writel(MSM_BOOT_UART_DM_DMRX_DEF_VALUE, MSM_BOOT_UART_DM_DMRX(uart_dm_base));
224 writel(MSM_BOOT_UART_DM_GCMD_ENA_STALE_EVT, MSM_BOOT_UART_DM_CR(uart_dm_base));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800225
226 return MSM_BOOT_UART_DM_E_SUCCESS;
227}
228
229/*
230 * UART Receive operation
231 * Reads a word from the RX FIFO.
232 */
233static unsigned int
Amol Jadia63aaff2012-02-01 15:51:50 -0800234msm_boot_uart_dm_read(uint32_t base, unsigned int *data, int wait)
Ajay Dudanib01e5062011-12-03 23:23:42 -0800235{
236 static int rx_last_snap_count = 0;
237 static int rx_chars_read_since_last_xfer = 0;
238
239 if (data == NULL) {
240 return MSM_BOOT_UART_DM_E_INVAL;
241 }
242
243 /* We will be polling RXRDY status bit */
Amol Jadia63aaff2012-02-01 15:51:50 -0800244 while (!(readl(MSM_BOOT_UART_DM_SR(base)) & MSM_BOOT_UART_DM_SR_RXRDY)) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800245 /* if this is not a blocking call, we'll just return */
246 if (!wait) {
247 return MSM_BOOT_UART_DM_E_RX_NOT_READY;
248 }
249 }
250
251 /* Check for Overrun error. We'll just reset Error Status */
Amol Jadia63aaff2012-02-01 15:51:50 -0800252 if (readl(MSM_BOOT_UART_DM_SR(base)) & MSM_BOOT_UART_DM_SR_UART_OVERRUN) {
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700253 writel(MSM_BOOT_UART_DM_CMD_RESET_ERR_STAT, MSM_BOOT_UART_DM_CR(base));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800254 }
255
256 /* RX FIFO is ready; read a word. */
Amol Jadia63aaff2012-02-01 15:51:50 -0800257 *data = readl(MSM_BOOT_UART_DM_RF(base, 0));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800258
259 /* increment the total count of chars we've read so far */
260 rx_chars_read_since_last_xfer += 4;
261
262 /* Rx transfer ends when one of the conditions is met:
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700263 * - The number of characters received since the end of the previous
264 * xfer equals the value written to DMRX at Transfer Initialization
Ajay Dudanib01e5062011-12-03 23:23:42 -0800265 * - A stale event occurred
266 */
267
268 /* If RX transfer has not ended yet */
269 if (rx_last_snap_count == 0) {
270 /* Check if we've received stale event */
Amol Jadia63aaff2012-02-01 15:51:50 -0800271 if (readl(MSM_BOOT_UART_DM_MISR(base)) & MSM_BOOT_UART_DM_RXSTALE) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800272 /* Send command to reset stale interrupt */
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700273 writel(MSM_BOOT_UART_DM_CMD_RES_STALE_INT, MSM_BOOT_UART_DM_CR(base));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800274 }
275
276 /* Check if we haven't read more than DMRX value */
277 else if ((unsigned int)rx_chars_read_since_last_xfer <
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700278 readl(MSM_BOOT_UART_DM_DMRX(base))) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800279 /* We can still continue reading before initializing RX transfer */
280 return MSM_BOOT_UART_DM_E_SUCCESS;
281 }
282
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700283 /* If we've reached here it means RX
284 * xfer end conditions been met
285 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800286
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700287 /* Read UART_DM_RX_TOTAL_SNAP register
288 * to know how many valid chars
289 * we've read so far since last transfer
290 */
Amol Jadia63aaff2012-02-01 15:51:50 -0800291 rx_last_snap_count = readl(MSM_BOOT_UART_DM_RX_TOTAL_SNAP(base));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800292
293 }
294
295 /* If there are still data left in FIFO we'll read them before
296 * initializing RX Transfer again */
297 if ((rx_last_snap_count - rx_chars_read_since_last_xfer) >= 0) {
298 return MSM_BOOT_UART_DM_E_SUCCESS;
299 }
300
Amol Jadia63aaff2012-02-01 15:51:50 -0800301 msm_boot_uart_dm_init_rx_transfer(base);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800302 rx_last_snap_count = 0;
303 rx_chars_read_since_last_xfer = 0;
304
305 return MSM_BOOT_UART_DM_E_SUCCESS;
306}
307
308/*
309 * UART transmit operation
310 */
311static unsigned int
Amol Jadia63aaff2012-02-01 15:51:50 -0800312msm_boot_uart_dm_write(uint32_t base, char *data, unsigned int num_of_chars)
Ajay Dudanib01e5062011-12-03 23:23:42 -0800313{
314 unsigned int tx_word_count = 0;
315 unsigned int tx_char_left = 0, tx_char = 0;
316 unsigned int tx_word = 0;
317 int i = 0;
318 char *tx_data = NULL;
Deepa Dinamani9965d1e2012-12-14 13:56:13 -0800319 uint8_t num_chars_written;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800320
321 if ((data == NULL) || (num_of_chars <= 0)) {
322 return MSM_BOOT_UART_DM_E_INVAL;
323 }
324
Deepa Dinamani9965d1e2012-12-14 13:56:13 -0800325 msm_boot_uart_calculate_num_chars_to_write(data, &num_of_chars);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800326
Deepa Dinamani9965d1e2012-12-14 13:56:13 -0800327 tx_data = data;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800328
329 /* Write to NO_CHARS_FOR_TX register number of characters
330 * to be transmitted. However, before writing TX_FIFO must
331 * be empty as indicated by TX_READY interrupt in IMR register
332 */
333
334 /* Check if transmit FIFO is empty.
335 * If not we'll wait for TX_READY interrupt. */
Amol Jadia63aaff2012-02-01 15:51:50 -0800336 if (!(readl(MSM_BOOT_UART_DM_SR(base)) & MSM_BOOT_UART_DM_SR_TXEMT)) {
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700337 while (!(readl(MSM_BOOT_UART_DM_ISR(base)) & MSM_BOOT_UART_DM_TX_READY)) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800338 udelay(1);
339 /* Kick watchdog? */
340 }
341 }
342
Figo Wange3594e72014-03-31 15:50:37 +0800343 //We need to make sure the DM_NO_CHARS_FOR_TX&DM_TF are are programmed atmoically.
344 enter_critical_section();
Ajay Dudanib01e5062011-12-03 23:23:42 -0800345 /* We are here. FIFO is ready to be written. */
346 /* Write number of characters to be written */
Amol Jadia63aaff2012-02-01 15:51:50 -0800347 writel(num_of_chars, MSM_BOOT_UART_DM_NO_CHARS_FOR_TX(base));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800348
349 /* Clear TX_READY interrupt */
Amol Jadia63aaff2012-02-01 15:51:50 -0800350 writel(MSM_BOOT_UART_DM_GCMD_RES_TX_RDY_INT, MSM_BOOT_UART_DM_CR(base));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800351
352 /* We use four-character word FIFO. So we need to divide data into
353 * four characters and write in UART_DM_TF register */
354 tx_word_count = (num_of_chars % 4) ? ((num_of_chars / 4) + 1) :
355 (num_of_chars / 4);
356 tx_char_left = num_of_chars;
357
358 for (i = 0; i < (int)tx_word_count; i++) {
359 tx_char = (tx_char_left < 4) ? tx_char_left : 4;
Deepa Dinamani9965d1e2012-12-14 13:56:13 -0800360 num_chars_written = pack_chars_into_words(tx_data, tx_char, &tx_word);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800361
362 /* Wait till TX FIFO has space */
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700363 while (!(readl(MSM_BOOT_UART_DM_SR(base)) & MSM_BOOT_UART_DM_SR_TXRDY)) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800364 udelay(1);
365 }
366
367 /* TX FIFO has space. Write the chars */
Amol Jadia63aaff2012-02-01 15:51:50 -0800368 writel(tx_word, MSM_BOOT_UART_DM_TF(base, 0));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800369 tx_char_left = num_of_chars - (i + 1) * 4;
Deepa Dinamani9965d1e2012-12-14 13:56:13 -0800370 tx_data = tx_data + num_chars_written;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800371 }
Figo Wange3594e72014-03-31 15:50:37 +0800372 exit_critical_section();
Ajay Dudanib01e5062011-12-03 23:23:42 -0800373
374 return MSM_BOOT_UART_DM_E_SUCCESS;
375}
376
377/* Defining functions that's exposed to outside world and in coformance to
378 * existing uart implemention. These functions are being called to initialize
379 * UART and print debug messages in bootloader.
380 */
Amol Jadia63aaff2012-02-01 15:51:50 -0800381void uart_dm_init(uint8_t id, uint32_t gsbi_base, uint32_t uart_dm_base)
Ajay Dudanib01e5062011-12-03 23:23:42 -0800382{
383 static uint8_t port = 0;
384 char *data = "Android Bootloader - UART_DM Initialized!!!\n";
385
Amol Jadia63aaff2012-02-01 15:51:50 -0800386 /* Configure the uart clock */
387 clock_config_uart_dm(id);
388 dsb();
389
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700390 /* Configure GPIO to provide connectivity between UART block
Amol Jadia63aaff2012-02-01 15:51:50 -0800391 product ports and chip pads */
392 gpio_config_uart_dm(id);
393 dsb();
394
395 /* Configure GSBI for UART_DM protocol.
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700396 * I2C on 2 ports, UART (without HS flow control) on the other 2.
397 * This is only on chips that have GSBI block
398 */
399 if(gsbi_base)
400 writel(GSBI_PROTOCOL_CODE_I2C_UART <<
401 GSBI_CTRL_REG_PROTOCOL_CODE_S,
402 GSBI_CTRL_REG(gsbi_base));
Amol Jadia63aaff2012-02-01 15:51:50 -0800403 dsb();
404
405 /* Configure clock selection register for tx and rx rates.
406 * Selecting 115.2k for both RX and TX.
407 */
408 writel(UART_DM_CLK_RX_TX_BIT_RATE, MSM_BOOT_UART_DM_CSR(uart_dm_base));
409 dsb();
410
411 /* Intialize UART_DM */
412 msm_boot_uart_dm_init(uart_dm_base);
413
414 msm_boot_uart_dm_write(uart_dm_base, data, 44);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800415
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700416 ASSERT(port < ARRAY_SIZE(port_lookup));
417 port_lookup[port++] = uart_dm_base;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800418
419 /* Set UART init flag */
420 uart_init_flag = 1;
421}
422
423/* UART_DM uses four character word FIFO where as UART core
424 * uses a character FIFO. so it's really inefficient to try
425 * to write single character. But that's how dprintf has been
426 * implemented.
427 */
428int uart_putc(int port, char c)
429{
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700430 uint32_t uart_base = port_lookup[port];
Ajay Dudanib01e5062011-12-03 23:23:42 -0800431
432 /* Don't do anything if UART is not initialized */
433 if (!uart_init_flag)
Amol Jadia63aaff2012-02-01 15:51:50 -0800434 return -1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800435
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700436 msm_boot_uart_dm_write(uart_base, &c, 1);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800437
438 return 0;
439}
440
441/* UART_DM uses four character word FIFO whereas uart_getc
442 * is supposed to read only one character. So we need to
443 * read a word and keep track of each character in the word.
444 */
445int uart_getc(int port, bool wait)
446{
447 int byte;
448 static unsigned int word = 0;
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700449 uint32_t uart_base = port_lookup[port];
Ajay Dudanib01e5062011-12-03 23:23:42 -0800450
451 /* Don't do anything if UART is not initialized */
452 if (!uart_init_flag)
Amol Jadia63aaff2012-02-01 15:51:50 -0800453 return -1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800454
455 if (!word) {
456 /* Read from FIFO only if it's a first read or all the four
457 * characters out of a word have been read */
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700458 if (msm_boot_uart_dm_read(uart_base, &word, wait) != MSM_BOOT_UART_DM_E_SUCCESS) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800459 return -1;
460 }
461
462 }
463
464 byte = (int)word & 0xff;
465 word = word >> 8;
466
467 return byte;
468}