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