blob: 01bcbb61659b2a2f9e28add86d3fc238b88a882a [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>
32#include <reg.h>
33#include <sys/types.h>
34#include <platform/iomap.h>
35#include <platform/irqs.h>
36#include <platform/interrupts.h>
37#include <platform/clock.h>
38#include <platform/gpio.h>
39#include <uart_dm.h>
40#include <gsbi.h>
41
42#ifndef NULL
43#define NULL 0
44#endif
45
46extern void dsb(void);
47
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
343 /* We are here. FIFO is ready to be written. */
344 /* Write number of characters to be written */
Amol Jadia63aaff2012-02-01 15:51:50 -0800345 writel(num_of_chars, MSM_BOOT_UART_DM_NO_CHARS_FOR_TX(base));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800346
347 /* Clear TX_READY interrupt */
Amol Jadia63aaff2012-02-01 15:51:50 -0800348 writel(MSM_BOOT_UART_DM_GCMD_RES_TX_RDY_INT, MSM_BOOT_UART_DM_CR(base));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800349
350 /* We use four-character word FIFO. So we need to divide data into
351 * four characters and write in UART_DM_TF register */
352 tx_word_count = (num_of_chars % 4) ? ((num_of_chars / 4) + 1) :
353 (num_of_chars / 4);
354 tx_char_left = num_of_chars;
355
356 for (i = 0; i < (int)tx_word_count; i++) {
357 tx_char = (tx_char_left < 4) ? tx_char_left : 4;
Deepa Dinamani9965d1e2012-12-14 13:56:13 -0800358 num_chars_written = pack_chars_into_words(tx_data, tx_char, &tx_word);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800359
360 /* Wait till TX FIFO has space */
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700361 while (!(readl(MSM_BOOT_UART_DM_SR(base)) & MSM_BOOT_UART_DM_SR_TXRDY)) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800362 udelay(1);
363 }
364
365 /* TX FIFO has space. Write the chars */
Amol Jadia63aaff2012-02-01 15:51:50 -0800366 writel(tx_word, MSM_BOOT_UART_DM_TF(base, 0));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800367 tx_char_left = num_of_chars - (i + 1) * 4;
Deepa Dinamani9965d1e2012-12-14 13:56:13 -0800368 tx_data = tx_data + num_chars_written;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800369 }
370
371 return MSM_BOOT_UART_DM_E_SUCCESS;
372}
373
374/* Defining functions that's exposed to outside world and in coformance to
375 * existing uart implemention. These functions are being called to initialize
376 * UART and print debug messages in bootloader.
377 */
Amol Jadia63aaff2012-02-01 15:51:50 -0800378void uart_dm_init(uint8_t id, uint32_t gsbi_base, uint32_t uart_dm_base)
Ajay Dudanib01e5062011-12-03 23:23:42 -0800379{
380 static uint8_t port = 0;
381 char *data = "Android Bootloader - UART_DM Initialized!!!\n";
382
Amol Jadia63aaff2012-02-01 15:51:50 -0800383 /* Configure the uart clock */
384 clock_config_uart_dm(id);
385 dsb();
386
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700387 /* Configure GPIO to provide connectivity between UART block
Amol Jadia63aaff2012-02-01 15:51:50 -0800388 product ports and chip pads */
389 gpio_config_uart_dm(id);
390 dsb();
391
392 /* Configure GSBI for UART_DM protocol.
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700393 * I2C on 2 ports, UART (without HS flow control) on the other 2.
394 * This is only on chips that have GSBI block
395 */
396 if(gsbi_base)
397 writel(GSBI_PROTOCOL_CODE_I2C_UART <<
398 GSBI_CTRL_REG_PROTOCOL_CODE_S,
399 GSBI_CTRL_REG(gsbi_base));
Amol Jadia63aaff2012-02-01 15:51:50 -0800400 dsb();
401
402 /* Configure clock selection register for tx and rx rates.
403 * Selecting 115.2k for both RX and TX.
404 */
405 writel(UART_DM_CLK_RX_TX_BIT_RATE, MSM_BOOT_UART_DM_CSR(uart_dm_base));
406 dsb();
407
408 /* Intialize UART_DM */
409 msm_boot_uart_dm_init(uart_dm_base);
410
411 msm_boot_uart_dm_write(uart_dm_base, data, 44);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800412
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700413 ASSERT(port < ARRAY_SIZE(port_lookup));
414 port_lookup[port++] = uart_dm_base;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800415
416 /* Set UART init flag */
417 uart_init_flag = 1;
418}
419
420/* UART_DM uses four character word FIFO where as UART core
421 * uses a character FIFO. so it's really inefficient to try
422 * to write single character. But that's how dprintf has been
423 * implemented.
424 */
425int uart_putc(int port, char c)
426{
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700427 uint32_t uart_base = port_lookup[port];
Ajay Dudanib01e5062011-12-03 23:23:42 -0800428
429 /* Don't do anything if UART is not initialized */
430 if (!uart_init_flag)
Amol Jadia63aaff2012-02-01 15:51:50 -0800431 return -1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800432
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700433 msm_boot_uart_dm_write(uart_base, &c, 1);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800434
435 return 0;
436}
437
438/* UART_DM uses four character word FIFO whereas uart_getc
439 * is supposed to read only one character. So we need to
440 * read a word and keep track of each character in the word.
441 */
442int uart_getc(int port, bool wait)
443{
444 int byte;
445 static unsigned int word = 0;
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700446 uint32_t uart_base = port_lookup[port];
Ajay Dudanib01e5062011-12-03 23:23:42 -0800447
448 /* Don't do anything if UART is not initialized */
449 if (!uart_init_flag)
Amol Jadia63aaff2012-02-01 15:51:50 -0800450 return -1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800451
452 if (!word) {
453 /* Read from FIFO only if it's a first read or all the four
454 * characters out of a word have been read */
Deepa Dinamanibce9d9e2012-05-17 13:53:17 -0700455 if (msm_boot_uart_dm_read(uart_base, &word, wait) != MSM_BOOT_UART_DM_E_SUCCESS) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800456 return -1;
457 }
458
459 }
460
461 byte = (int)word & 0xff;
462 word = word >> 8;
463
464 return byte;
465}