Bikas Gurung | d1aa590 | 2010-10-01 23:45:33 -0700 | [diff] [blame^] | 1 | /* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
|
| 2 |
|
| 3 | * Redistribution and use in source and binary forms, with or without
|
| 4 | * modification, are permitted provided that the following conditions are
|
| 5 | * met:
|
| 6 | * * 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 Code Aurora Forum, Inc. 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.
|
| 15 | *
|
| 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 <platform/iomap.h>
|
| 34 | #include <platform/irqs.h>
|
| 35 | #include <platform/interrupts.h>
|
| 36 | #include <platform/gpio_hw.h>
|
| 37 | #include <dev/uart.h>
|
| 38 | #include "uart_dm.h"
|
| 39 |
|
| 40 |
|
| 41 | #ifndef NULL
|
| 42 | #define NULL 0
|
| 43 | #endif
|
| 44 |
|
| 45 | /* Note:
|
| 46 | * This is a basic implementation of UART_DM protocol. More focus has been
|
| 47 | * given on simplicity than efficiency. Few of the things to be noted are:
|
| 48 | * - RX path may not be suitable for multi-threaded scenaraio because of the
|
| 49 | * use of static variables. TX path shouldn't have any problem though. If
|
| 50 | * multi-threaded support is required, a simple data-structure can
|
| 51 | * be maintained for each thread.
|
| 52 | * - Right now we are using polling method than interrupt based.
|
| 53 | * - We are using legacy UART protocol without Data Mover.
|
| 54 | * - Not all interrupts and error events are handled.
|
| 55 | * - While waiting Watchdog hasn't been taken into consideration.
|
| 56 | */
|
| 57 |
|
| 58 |
|
| 59 | #define PACK_CHARS_INTO_WORDS(a, cnt, word) { \
|
| 60 | word = 0; \
|
| 61 | for(int j=0; j < (int)cnt; j++) \
|
| 62 | { \
|
| 63 | word |= (a[j] & 0xff) \
|
| 64 | << (j * 8); \
|
| 65 | } \
|
| 66 | }
|
| 67 |
|
| 68 |
|
| 69 | /* Static Function Prototype Declarations */
|
| 70 | static unsigned int msm_boot_uart_config_gpios(void);
|
| 71 | static unsigned int msm_boot_uart_dm_config_clock(void);
|
| 72 | static unsigned int msm_boot_uart_dm_gsbi_init(void);
|
| 73 | static unsigned int msm_boot_uart_replace_lr_with_cr(char* data_in,
|
| 74 | int num_of_chars,
|
| 75 | char *data_out,
|
| 76 | int *num_of_chars_out);
|
| 77 | static unsigned int msm_boot_uart_dm_init(void);
|
| 78 | static unsigned int msm_boot_uart_dm_read(unsigned int* data,
|
| 79 | int wait);
|
| 80 | static unsigned int msm_boot_uart_dm_write(char* data,
|
| 81 | unsigned int num_of_chars);
|
| 82 | static unsigned int msm_boot_uart_dm_init_rx_transfer(void);
|
| 83 | static unsigned int msm_boot_uart_dm_reset(void);
|
| 84 |
|
| 85 |
|
| 86 | /* Extern functions */
|
| 87 | void clock_config(unsigned int ns, unsigned int md,
|
| 88 | unsigned int ns_addr, unsigned int md_addr);
|
| 89 |
|
| 90 | void gpio_tlmm_config(uint32_t gpio, uint8_t func,
|
| 91 | uint8_t dir, uint8_t pull,
|
| 92 | uint8_t drvstr, uint32_t enable );
|
| 93 |
|
| 94 | void udelay(unsigned usecs);
|
| 95 |
|
| 96 |
|
| 97 | /*
|
| 98 | * Helper function to replace Line Feed char "\n" with
|
| 99 | * Carriage Return "\r\n".
|
| 100 | * Currently keeping it simple than efficient
|
| 101 | */
|
| 102 | static unsigned int msm_boot_uart_replace_lr_with_cr(char* data_in,
|
| 103 | int num_of_chars,
|
| 104 | char *data_out,
|
| 105 | int *num_of_chars_out )
|
| 106 | {
|
| 107 | int i = 0, j = 0;
|
| 108 |
|
| 109 | if ((data_in == NULL) || (data_out == NULL) || (num_of_chars < 0))
|
| 110 | {
|
| 111 | return MSM_BOOT_UART_DM_E_INVAL;
|
| 112 | }
|
| 113 |
|
| 114 | for (i=0, j=0; i < num_of_chars; i++, j++)
|
| 115 | {
|
| 116 | if ( data_in[i] == '\n' )
|
| 117 | {
|
| 118 | data_out[j++] = '\r';
|
| 119 | }
|
| 120 |
|
| 121 | data_out[j] = data_in[i];
|
| 122 | }
|
| 123 |
|
| 124 | *num_of_chars_out = j;
|
| 125 |
|
| 126 | return MSM_BOOT_UART_DM_E_SUCCESS;
|
| 127 | }
|
| 128 |
|
| 129 |
|
| 130 | static unsigned int msm_boot_uart_dm_config_gpios(void)
|
| 131 | {
|
| 132 | /* GPIO Pin: MSM_BOOT_UART_DM_RX_GPIO (117)
|
| 133 | Function: 2
|
| 134 | Direction: IN
|
| 135 | Pull: No PULL
|
| 136 | Drive Strength: 8 ma
|
| 137 | Output Enable: Disable
|
| 138 | */
|
| 139 | gpio_tlmm_config(MSM_BOOT_UART_DM_RX_GPIO, 2, GPIO_INPUT,
|
| 140 | GPIO_NO_PULL, GPIO_8MA, GPIO_DISABLE);
|
| 141 |
|
| 142 | /* GPIO Pin: MSM_BOOT_UART_DM_TX_GPIO (118)
|
| 143 | Function: 2
|
| 144 | Direction: OUT
|
| 145 | Pull: No PULL
|
| 146 | Drive Strength: 8 ma
|
| 147 | Output Enable: Disable
|
| 148 | */
|
| 149 | gpio_tlmm_config(MSM_BOOT_UART_DM_TX_GPIO, 2, GPIO_OUTPUT,
|
| 150 | GPIO_NO_PULL, GPIO_8MA, GPIO_DISABLE);
|
| 151 |
|
| 152 | return MSM_BOOT_UART_DM_E_SUCCESS;
|
| 153 | }
|
| 154 |
|
| 155 |
|
| 156 |
|
| 157 | static unsigned int msm_boot_uart_dm_config_clock(void)
|
| 158 | {
|
| 159 | unsigned int curr_value = 0;
|
| 160 |
|
| 161 | /* Vote for PLL8 to be enabled */
|
| 162 | curr_value = readl(MSM_BOOT_PLL_ENABLE_SC0);
|
| 163 | curr_value |= (1 << 8);
|
| 164 | writel(curr_value, MSM_BOOT_PLL_ENABLE_SC0);
|
| 165 |
|
| 166 | /* Proceed only after PLL is enabled */
|
| 167 | while (!(readl(MSM_BOOT_PLL8_STATUS) & (1<<16)));
|
| 168 |
|
| 169 | /* PLL8 is enabled. Enable gsbi_uart_clk */
|
| 170 |
|
| 171 | /* GSBI clock frequencies for UART protocol
|
| 172 | * Operating mode gsbi_uart_clk
|
| 173 | * UART up to 115.2 Kbps 1.8432 MHz
|
| 174 | * UART up to 460.8 Kbps 7.3728 MHz
|
| 175 | * UART up to 4 Mbit/s 64 MHz
|
| 176 | *
|
| 177 |
|
| 178 | * Choosing lowest supported value
|
| 179 | * Rate (KHz) NS MD
|
| 180 | * 3686400 0xFD940043 0x0006FD8E
|
| 181 | */
|
| 182 |
|
| 183 | clock_config(0xFD940043, 0x0006FD8E,
|
| 184 | MSM_BOOT_UART_DM_APPS_NS,
|
| 185 | MSM_BOOT_UART_DM_APPS_MD);
|
| 186 |
|
| 187 | /* Enable gsbi_pclk */
|
| 188 | writel(0x10, MSM_BOOT_UART_DM_GSBI_HCLK_CTL);
|
| 189 |
|
| 190 | return MSM_BOOT_UART_DM_E_SUCCESS;
|
| 191 | }
|
| 192 |
|
| 193 |
|
| 194 | /*
|
| 195 | * Initialize and configure GSBI for operation
|
| 196 | */
|
| 197 | static unsigned int msm_boot_uart_dm_gsbi_init(void)
|
| 198 | {
|
| 199 | /* Configure the clock block */
|
| 200 | msm_boot_uart_dm_config_clock();
|
| 201 |
|
| 202 | /* Configure TLMM/GPIO to provide connectivity between GSBI
|
| 203 | product ports and chip pads */
|
| 204 | msm_boot_uart_dm_config_gpios();
|
| 205 |
|
| 206 |
|
| 207 | /* Configure Data Mover for GSBI operation.
|
| 208 | * Currently not supported. */
|
| 209 |
|
| 210 | /* Configure GSBI for UART_DM protocol.
|
| 211 | * I2C on 2 ports, UART (without HS flow control) on the other 2. */
|
| 212 | writel(0x60, MSM_BOOT_GSBI_CTRL_REG);
|
| 213 |
|
| 214 | return MSM_BOOT_UART_DM_E_SUCCESS;
|
| 215 | }
|
| 216 |
|
| 217 | /*
|
| 218 | * Reset the UART
|
| 219 | */
|
| 220 | static unsigned int msm_boot_uart_dm_reset(void)
|
| 221 | {
|
| 222 | writel(MSM_BOOT_UART_DM_CMD_RESET_RX, MSM_BOOT_UART_DM_CR);
|
| 223 | writel(MSM_BOOT_UART_DM_CMD_RESET_TX, MSM_BOOT_UART_DM_CR);
|
| 224 | writel(MSM_BOOT_UART_DM_CMD_RESET_ERR_STAT, MSM_BOOT_UART_DM_CR);
|
| 225 | writel(MSM_BOOT_UART_DM_CMD_RES_TX_ERR, MSM_BOOT_UART_DM_CR);
|
| 226 | writel(MSM_BOOT_UART_DM_CMD_RES_STALE_INT, MSM_BOOT_UART_DM_CR);
|
| 227 |
|
| 228 | return MSM_BOOT_UART_DM_E_SUCCESS;
|
| 229 | }
|
| 230 |
|
| 231 |
|
| 232 | /*
|
| 233 | * Initialize UART_DM - configure clock and required registers.
|
| 234 | */
|
| 235 | static unsigned int msm_boot_uart_dm_init(void)
|
| 236 | {
|
| 237 | /* Configure GSB12 for uart dm */
|
| 238 | msm_boot_uart_dm_gsbi_init();
|
| 239 |
|
| 240 |
|
| 241 | /* Configure clock selection register for tx and rx rates.
|
| 242 | * Selecting 115.2k for both RX and TX */
|
| 243 | writel(MSM_BOOT_UART_DM_RX_TX_BIT_RATE, MSM_BOOT_UART_DM_CSR);
|
| 244 |
|
| 245 | /* Configure UART mode registers MR1 and MR2 */
|
| 246 | /* Hardware flow control isn't supported */
|
| 247 | writel(0x0, MSM_BOOT_UART_DM_MR1);
|
| 248 |
|
| 249 | /* 8-N-1 configuration: 8 data bits - No parity - 1 stop bit */
|
| 250 | writel(MSM_BOOT_UART_DM_8_N_1_MODE, MSM_BOOT_UART_DM_MR2);
|
| 251 |
|
| 252 | /* Configure Interrupt Mask register IMR */
|
| 253 | writel(MSM_BOOT_UART_DM_IMR_ENABLED, MSM_BOOT_UART_DM_IMR);
|
| 254 |
|
| 255 | /* Configure Tx and Rx watermarks configuration registers */
|
| 256 | /* TX watermark value is set to 0 - interrupt is generated when
|
| 257 | * FIFO level is less than or equal to 0 */
|
| 258 | writel(MSM_BOOT_UART_DM_TFW_VALUE, MSM_BOOT_UART_DM_TFWR);
|
| 259 |
|
| 260 | /* RX watermark value*/
|
| 261 | writel(MSM_BOOT_UART_DM_RFW_VALUE, MSM_BOOT_UART_DM_RFWR);
|
| 262 |
|
| 263 | /* Configure Interrupt Programming Register*/
|
| 264 | /* Set initial Stale timeout value*/
|
| 265 | writel(MSM_BOOT_UART_DM_STALE_TIMEOUT_LSB, MSM_BOOT_UART_DM_IPR);
|
| 266 |
|
| 267 | /* Configure IRDA if required */
|
| 268 | /* Disabling IRDA mode */
|
| 269 | writel(0x0, MSM_BOOT_UART_DM_IRDA);
|
| 270 |
|
| 271 | /* Configure and enable sim interface if required */
|
| 272 |
|
| 273 | /* Configure hunt character value in HCR register */
|
| 274 | /* Keep it in reset state */
|
| 275 | writel(0x0, MSM_BOOT_UART_DM_HCR);
|
| 276 |
|
| 277 | /* Configure Rx FIFO base address */
|
| 278 | /* Both TX/RX shares same SRAM and default is half-n-half.
|
| 279 | * Sticking with default value now.
|
| 280 | * As such RAM size is (2^RAM_ADDR_WIDTH, 32-bit entries).
|
| 281 | * We have found RAM_ADDR_WIDTH = 0x7f */
|
| 282 |
|
| 283 | /* Issue soft reset command */
|
| 284 | msm_boot_uart_dm_reset();
|
| 285 |
|
| 286 | /* Enable/Disable Rx/Tx DM interfaces */
|
| 287 | /* Data Mover not currently utilized. */
|
| 288 | writel(0x0, MSM_BOOT_UART_DM_DMEN);
|
| 289 |
|
| 290 |
|
| 291 | /* Enable transmitter and receiver */
|
| 292 | writel(MSM_BOOT_UART_DM_CR_RX_ENABLE, MSM_BOOT_UART_DM_CR);
|
| 293 | writel(MSM_BOOT_UART_DM_CR_TX_ENABLE, MSM_BOOT_UART_DM_CR);
|
| 294 |
|
| 295 | /* Initialize Receive Path */
|
| 296 | msm_boot_uart_dm_init_rx_transfer();
|
| 297 |
|
| 298 | return MSM_BOOT_UART_DM_E_SUCCESS;
|
| 299 | }
|
| 300 |
|
| 301 |
|
| 302 | /*
|
| 303 | * Initialize Receive Path
|
| 304 | */
|
| 305 | static unsigned int msm_boot_uart_dm_init_rx_transfer(void)
|
| 306 | {
|
| 307 | writel(MSM_BOOT_UART_DM_GCMD_DIS_STALE_EVT, MSM_BOOT_UART_DM_CR);
|
| 308 | writel(MSM_BOOT_UART_DM_CMD_RES_STALE_INT, MSM_BOOT_UART_DM_CR);
|
| 309 | writel(MSM_BOOT_UART_DM_DMRX_DEF_VALUE, MSM_BOOT_UART_DM_DMRX);
|
| 310 | writel(MSM_BOOT_UART_DM_GCMD_ENA_STALE_EVT, MSM_BOOT_UART_DM_CR);
|
| 311 |
|
| 312 | return MSM_BOOT_UART_DM_E_SUCCESS;
|
| 313 | }
|
| 314 |
|
| 315 | /*
|
| 316 | * UART Receive operation
|
| 317 | * Reads a word from the RX FIFO.
|
| 318 | */
|
| 319 | static unsigned int msm_boot_uart_dm_read(unsigned int* data, int wait)
|
| 320 | {
|
| 321 | static int rx_last_snap_count = 0;
|
| 322 | static int rx_chars_read_since_last_xfer = 0;
|
| 323 |
|
| 324 | if (data == NULL)
|
| 325 | {
|
| 326 | return MSM_BOOT_UART_DM_E_INVAL;
|
| 327 | }
|
| 328 |
|
| 329 |
|
| 330 |
|
| 331 | /* We will be polling RXRDY status bit */
|
| 332 | while (!(readl(MSM_BOOT_UART_DM_SR) & MSM_BOOT_UART_DM_SR_RXRDY))
|
| 333 | {
|
| 334 | /* if this is not a blocking call, we'll just return */
|
| 335 | if (!wait)
|
| 336 | {
|
| 337 | return MSM_BOOT_UART_DM_E_RX_NOT_READY;
|
| 338 | }
|
| 339 | }
|
| 340 |
|
| 341 | /* Check for Overrun error. We'll just reset Error Status */
|
| 342 | if (readl(MSM_BOOT_UART_DM_SR) & MSM_BOOT_UART_DM_SR_UART_OVERRUN)
|
| 343 | {
|
| 344 | writel(MSM_BOOT_UART_DM_CMD_RESET_ERR_STAT, MSM_BOOT_UART_DM_CR);
|
| 345 | }
|
| 346 |
|
| 347 | /* RX FIFO is ready; read a word. */
|
| 348 | *data = readl(MSM_BOOT_UART_DM_RF(0));
|
| 349 |
|
| 350 | /* increment the total count of chars we've read so far */
|
| 351 | rx_chars_read_since_last_xfer += 4;
|
| 352 |
|
| 353 | /* Rx transfer ends when one of the conditions is met:
|
| 354 | * - The number of characters received since the end of the previous xfer
|
| 355 | * equals the value written to DMRX at Transfer Initialization
|
| 356 | * - A stale event occurred
|
| 357 | */
|
| 358 |
|
| 359 | /* If RX transfer has not ended yet */
|
| 360 | if (rx_last_snap_count == 0)
|
| 361 | {
|
| 362 | /* Check if we've received stale event */
|
| 363 | if (readl(MSM_BOOT_UART_DM_MISR) & MSM_BOOT_UART_DM_RXSTALE)
|
| 364 | {
|
| 365 | /* Send command to reset stale interrupt */
|
| 366 | writel(MSM_BOOT_UART_DM_CMD_RES_STALE_INT, MSM_BOOT_UART_DM_CR);
|
| 367 | }
|
| 368 |
|
| 369 | /* Check if we haven't read more than DMRX value */
|
| 370 | else if ((unsigned int)rx_chars_read_since_last_xfer <
|
| 371 | readl(MSM_BOOT_UART_DM_DMRX))
|
| 372 | {
|
| 373 | /* We can still continue reading before initializing RX transfer */
|
| 374 | return MSM_BOOT_UART_DM_E_SUCCESS;
|
| 375 | }
|
| 376 |
|
| 377 | /* If we've reached here it means RX xfer end conditions been met */
|
| 378 |
|
| 379 | /* Read UART_DM_RX_TOTAL_SNAP register to know how many valid chars
|
| 380 | * we've read so far since last transfer */
|
| 381 | rx_last_snap_count = readl(MSM_BOOT_UART_DM_RX_TOTAL_SNAP);
|
| 382 |
|
| 383 | }
|
| 384 |
|
| 385 | /* If there are still data left in FIFO we'll read them before
|
| 386 | * initializing RX Transfer again */
|
| 387 | if ((rx_last_snap_count - rx_chars_read_since_last_xfer) >= 0 )
|
| 388 | {
|
| 389 | return MSM_BOOT_UART_DM_E_SUCCESS;
|
| 390 | }
|
| 391 |
|
| 392 | msm_boot_uart_dm_init_rx_transfer();
|
| 393 | rx_last_snap_count = 0;
|
| 394 | rx_chars_read_since_last_xfer = 0;
|
| 395 |
|
| 396 | return MSM_BOOT_UART_DM_E_SUCCESS;
|
| 397 | }
|
| 398 |
|
| 399 |
|
| 400 | /*
|
| 401 | * UART transmit operation
|
| 402 | */
|
| 403 | static unsigned int msm_boot_uart_dm_write(char* data,
|
| 404 | unsigned int num_of_chars)
|
| 405 | {
|
| 406 | unsigned int tx_word_count = 0;
|
| 407 | unsigned int tx_char_left = 0, tx_char = 0;
|
| 408 | unsigned int tx_word = 0;
|
| 409 | int i = 0;
|
| 410 | char* tx_data = NULL;
|
| 411 | char new_data[1024];
|
| 412 |
|
| 413 | if ((data == NULL) || (num_of_chars <= 0))
|
| 414 | {
|
| 415 | return MSM_BOOT_UART_DM_E_INVAL;
|
| 416 | }
|
| 417 |
|
| 418 | /* Replace line-feed (/n) with carriage-return + line-feed (/r/n) */
|
| 419 |
|
| 420 | msm_boot_uart_replace_lr_with_cr(data, num_of_chars, new_data, &i);
|
| 421 |
|
| 422 | tx_data = new_data;
|
| 423 | num_of_chars = i;
|
| 424 |
|
| 425 | /* Write to NO_CHARS_FOR_TX register number of characters
|
| 426 | * to be transmitted. However, before writing TX_FIFO must
|
| 427 | * be empty as indicated by TX_READY interrupt in IMR register
|
| 428 | */
|
| 429 |
|
| 430 | /* Check if transmit FIFO is empty.
|
| 431 | * If not we'll wait for TX_READY interrupt. */
|
| 432 | if (!(readl(MSM_BOOT_UART_DM_SR) & MSM_BOOT_UART_DM_SR_TXEMT))
|
| 433 | {
|
| 434 | while (!(readl(MSM_BOOT_UART_DM_ISR) & MSM_BOOT_UART_DM_TX_READY))
|
| 435 | {
|
| 436 | udelay(1);
|
| 437 | /* Kick watchdog? */
|
| 438 | }
|
| 439 | }
|
| 440 |
|
| 441 | /* We are here. FIFO is ready to be written. */
|
| 442 | /* Write number of characters to be written */
|
| 443 | writel(num_of_chars, MSM_BOOT_UART_DM_NO_CHARS_FOR_TX);
|
| 444 |
|
| 445 | /* Clear TX_READY interrupt */
|
| 446 | writel(MSM_BOOT_UART_DM_GCMD_RES_TX_RDY_INT, MSM_BOOT_UART_DM_CR);
|
| 447 |
|
| 448 | /* We use four-character word FIFO. So we need to divide data into
|
| 449 | * four characters and write in UART_DM_TF register */
|
| 450 | tx_word_count = (num_of_chars % 4)? ((num_of_chars / 4) + 1) :
|
| 451 | (num_of_chars / 4);
|
| 452 | tx_char_left = num_of_chars;
|
| 453 |
|
| 454 | for (i = 0; i < (int)tx_word_count; i++)
|
| 455 | {
|
| 456 | tx_char = (tx_char_left < 4)? tx_char_left : 4;
|
| 457 | PACK_CHARS_INTO_WORDS(tx_data, tx_char, tx_word);
|
| 458 |
|
| 459 | /* Wait till TX FIFO has space */
|
| 460 | while (!(readl(MSM_BOOT_UART_DM_SR) & MSM_BOOT_UART_DM_SR_TXRDY))
|
| 461 | {
|
| 462 | udelay(1);
|
| 463 | }
|
| 464 |
|
| 465 | /* TX FIFO has space. Write the chars */
|
| 466 | writel(tx_word, MSM_BOOT_UART_DM_TF(0));
|
| 467 | tx_char_left = num_of_chars - (i+1)*4;
|
| 468 | tx_data = tx_data + 4;
|
| 469 | }
|
| 470 |
|
| 471 | return MSM_BOOT_UART_DM_E_SUCCESS;
|
| 472 | }
|
| 473 |
|
| 474 |
|
| 475 | /* Defining functions that's exposed to outside world and in coformance to
|
| 476 | * existing uart implemention. These functions are being called to initialize
|
| 477 | * UART and print debug messages in bootloader. */
|
| 478 |
|
| 479 | void uart_init(void)
|
| 480 | {
|
| 481 | char *data = "Android Bootloader - UART_DM Initialized!!!\n";
|
| 482 |
|
| 483 | msm_boot_uart_dm_init();
|
| 484 | msm_boot_uart_dm_write(data, 44);
|
| 485 |
|
| 486 | }
|
| 487 |
|
| 488 | /* UART_DM uses four character word FIFO where as UART core
|
| 489 | * uses a character FIFO. so it's really inefficient to try
|
| 490 | * to write single character. But that's how dprintf has been
|
| 491 | * implemented.
|
| 492 | */
|
| 493 | int uart_putc(int port, char c)
|
| 494 | {
|
| 495 |
|
| 496 | msm_boot_uart_dm_write(&c, 1);
|
| 497 |
|
| 498 | return 0;
|
| 499 | }
|
| 500 |
|
| 501 | /* UART_DM uses four character word FIFO whereas uart_getc
|
| 502 | * is supposed to read only one character. So we need to
|
| 503 | * read a word and keep track of each character in the word.
|
| 504 | */
|
| 505 | int uart_getc(int port, bool wait)
|
| 506 | {
|
| 507 | int byte;
|
| 508 | static unsigned int word = 0;
|
| 509 |
|
| 510 | if (!word)
|
| 511 | {
|
| 512 | /* Read from FIFO only if it's a first read or all the four
|
| 513 | * characters out of a word have been read */
|
| 514 | if (msm_boot_uart_dm_read( &word, wait) != MSM_BOOT_UART_DM_E_SUCCESS)
|
| 515 | {
|
| 516 | return -1;
|
| 517 | }
|
| 518 |
|
| 519 | }
|
| 520 |
|
| 521 | byte = (int) word & 0xff;
|
| 522 | word = word >> 8;
|
| 523 |
|
| 524 | return byte;
|
| 525 | }
|
| 526 |
|