new file mode 100644
@@ -0,0 +1,20 @@
+#
+# SUART Kernel Configuration
+#
+
+config SERIAL_SUART_OMAPL_PRU
+ depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850
+ select SERIAL_CORE
+ tristate "PRU based SoftUART emulation for OMAPL"
+ ---help---
+ Enable this to emulate a UART controller on the PRU of OMAPL.
+ Enable this to emulate a UART controller on the PRU of OMAPL.
+ If not sure, mark N
+
+config OMAPL_SUART_MCASP
+ int "McASP number"
+ depends on ARCH_DAVINCI && ARCH_DAVINCI_DA830 && SERIAL_SUART_OMAPL_PRU
+ default "0"
+ ---help---
+ Enter the McASP number to use with SUART (0, 1 or 2).
+ You will need to recompile the kernel if this is changed.
new file mode 100644
@@ -0,0 +1,9 @@
+#
+# Makefile for SoftUART emulation
+#
+
+suart_emu-objs := ti_omapl_pru_suart.o \
+ suart_api.o \
+ suart_utils.o
+
+obj-$(CONFIG_SERIAL_SUART_OMAPL_PRU) += suart_emu.o
new file mode 100644
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: subhasish@mistralsolutions.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef _OMAPL_SUART_BOARD_H_
+#define _OMAPL_SUART_BOARD_H_
+
+#define PRU_SUART1_CONFIG_DUPLEX (ePRU_SUART_HALF_TX | ePRU_SUART_HALF_RX)
+#define PRU_SUART1_CONFIG_RX_SER (PRU_SUART_SERIALIZER_NONE)
+#define PRU_SUART1_CONFIG_TX_SER (PRU_SUART_SERIALIZER_NONE)
+
+#define PRU_SUART2_CONFIG_DUPLEX (ePRU_SUART_HALF_TX | ePRU_SUART_HALF_RX)
+#define PRU_SUART2_CONFIG_RX_SER (PRU_SUART_SERIALIZER_7)
+#define PRU_SUART2_CONFIG_TX_SER (PRU_SUART_SERIALIZER_8)
+
+#define PRU_SUART3_CONFIG_DUPLEX (ePRU_SUART_HALF_TX | ePRU_SUART_HALF_RX)
+#define PRU_SUART3_CONFIG_RX_SER (PRU_SUART_SERIALIZER_9)
+#define PRU_SUART3_CONFIG_TX_SER (PRU_SUART_SERIALIZER_10)
+
+#define PRU_SUART4_CONFIG_DUPLEX (ePRU_SUART_HALF_TX | ePRU_SUART_HALF_RX)
+#define PRU_SUART4_CONFIG_RX_SER (PRU_SUART_SERIALIZER_NONE)
+#define PRU_SUART4_CONFIG_TX_SER (PRU_SUART_SERIALIZER_NONE)
+
+#define PRU_SUART5_CONFIG_DUPLEX (ePRU_SUART_HALF_TX | ePRU_SUART_HALF_RX)
+#define PRU_SUART5_CONFIG_RX_SER (PRU_SUART_SERIALIZER_NONE)
+#define PRU_SUART5_CONFIG_TX_SER (PRU_SUART_SERIALIZER_NONE)
+
+#define PRU_SUART6_CONFIG_DUPLEX (ePRU_SUART_HALF_TX | ePRU_SUART_HALF_RX)
+#define PRU_SUART6_CONFIG_RX_SER (PRU_SUART_SERIALIZER_NONE)
+#define PRU_SUART6_CONFIG_TX_SER (PRU_SUART_SERIALIZER_NONE)
+
+#define PRU_SUART7_CONFIG_DUPLEX (ePRU_SUART_HALF_TX | ePRU_SUART_HALF_RX)
+#define PRU_SUART7_CONFIG_RX_SER (PRU_SUART_SERIALIZER_NONE)
+#define PRU_SUART7_CONFIG_TX_SER (PRU_SUART_SERIALIZER_NONE)
+
+#define PRU_SUART8_CONFIG_DUPLEX (ePRU_SUART_HALF_TX | ePRU_SUART_HALF_RX)
+#define PRU_SUART8_CONFIG_RX_SER (PRU_SUART_SERIALIZER_NONE)
+#define PRU_SUART8_CONFIG_TX_SER (PRU_SUART_SERIALIZER_NONE)
+
+#endif /* End of _OMAPL_SUART_BOARD_H_ */
new file mode 100644
@@ -0,0 +1,2758 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: Jitendra Kumar <jitendra@mistralsolutions.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/types.h>
+#include <mach/pru/pru.h>
+#include "suart_api.h"
+#include "suart_pru_regs.h"
+#include "omapl_suart_board.h"
+#include "suart_utils.h"
+#include "suart_err.h"
+
+static u8 gUartStatuTable[8];
+static arm_pru_iomap pru_arm_iomap;
+
+#if (PRU_ACTIVE == BOTH_PRU)
+void pru_set_ram_data(arm_pru_iomap *arm_iomap_pru)
+{
+ PRU_SUART_RegsOvly pru_suart_regs =
+ (PRU_SUART_RegsOvly) arm_iomap_pru->pru_io_addr;
+ u32 *pu32SrCtlAddr = (u32 *)(arm_iomap_pru->mcasp_io_addr + 0x180);
+ pru_suart_tx_cntx_priv *pru_suart_tx_priv = NULL;
+ pru_suart_rx_cntx_priv *pru_suart_rx_priv = NULL;
+ u8 *pu32_pru_ram_base = (u8 *)arm_iomap_pru->pru_io_addr;
+ /* RX PRU - 0 Chanel 0 context information */
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_RX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART1_CONFIG_RX_SER);
+ pru_suart_regs->CH_Config1.over_sampling = SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART1_CONFIG_RX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART1_CONFIG_RX_SER)) =
+ MCASP_SRCTL_RX_MODE;
+#endif
+ /*
+ * RX is active by default, write the dummy received data at
+ * PRU RAM addr 0x1FC to avoid memory corruption.
+ */
+ pru_suart_regs->CH_TXRXData = RX_DEFAULT_DATA_DUMP_ADDR;
+ pru_suart_regs->Reserved1 = 0;
+ /* SUART1 RX context base addr */
+ pru_suart_rx_priv = (pru_suart_rx_cntx_priv *)
+ (pu32_pru_ram_base + 0x090);
+ pru_suart_rx_priv->asp_rbuf_base =
+ (u32)(MCASP_RBUF_BASE_ADDR + (PRU_SUART1_CONFIG_RX_SER << 2));
+ pru_suart_rx_priv->asp_rsrctl_base = (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART1_CONFIG_RX_SER << 2));
+
+ /* Chanel 1 context information */
+ pru_suart_regs++;
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_RX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART2_CONFIG_RX_SER);
+ pru_suart_regs->CH_Config1.over_sampling = SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART2_CONFIG_RX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART2_CONFIG_RX_SER)) =
+ MCASP_SRCTL_RX_MODE;
+#endif
+ /* RX is active by default, write the dummy received data
+ * at PRU RAM addr 0x1FC to avoid memory corruption */
+ pru_suart_regs->CH_TXRXData = RX_DEFAULT_DATA_DUMP_ADDR;
+ pru_suart_regs->Reserved1 = 0;
+ /* SUART2 RX context base addr */
+ pru_suart_rx_priv = (pru_suart_rx_cntx_priv *)
+ (pu32_pru_ram_base + 0x0B0);
+ pru_suart_rx_priv->asp_rbuf_base = (u32)(MCASP_RBUF_BASE_ADDR +
+ (PRU_SUART2_CONFIG_RX_SER << 2));
+ pru_suart_rx_priv->asp_rsrctl_base = (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART2_CONFIG_RX_SER << 2));
+
+ /* Chanel 2 context information */
+ pru_suart_regs++;
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_RX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART3_CONFIG_RX_SER);
+ pru_suart_regs->CH_Config1.over_sampling = SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART3_CONFIG_RX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART3_CONFIG_RX_SER)) =
+ MCASP_SRCTL_RX_MODE;
+#endif
+ /* RX is active by default, write the dummy
+ * received data at PRU RAM addr 0x1FC to avoid memory corruption */
+ pru_suart_regs->CH_TXRXData = RX_DEFAULT_DATA_DUMP_ADDR;
+ pru_suart_regs->Reserved1 = 0;
+ pru_suart_rx_priv = (pru_suart_rx_cntx_priv *)
+ (pu32_pru_ram_base + 0x0D0);
+ pru_suart_rx_priv->asp_rbuf_base = (u32)(MCASP_RBUF_BASE_ADDR +
+ (PRU_SUART3_CONFIG_RX_SER << 2));
+ pru_suart_rx_priv->asp_rsrctl_base = (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART3_CONFIG_RX_SER << 2));
+
+ /* Chanel 3 context information */
+ pru_suart_regs++;
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_RX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART4_CONFIG_RX_SER);
+ pru_suart_regs->CH_Config1.over_sampling = SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART4_CONFIG_RX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART4_CONFIG_RX_SER)) =
+ MCASP_SRCTL_RX_MODE;
+#endif
+ /* RX is active by default, write the dummy received data
+ * at PRU RAM addr 0x1FC to avoid memory corruption */
+ pru_suart_regs->CH_TXRXData = RX_DEFAULT_DATA_DUMP_ADDR;
+ pru_suart_regs->Reserved1 = 0;
+ /* SUART4 RX context base addr */
+ pru_suart_rx_priv = (pru_suart_rx_cntx_priv *)
+ (pu32_pru_ram_base + 0x0F0);
+ pru_suart_rx_priv->asp_rbuf_base = (u32)(MCASP_RBUF_BASE_ADDR +
+ (PRU_SUART4_CONFIG_RX_SER << 2));
+ pru_suart_rx_priv->asp_rsrctl_base = (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART4_CONFIG_RX_SER << 2));
+
+ /* Chanel 4 context information */
+ pru_suart_regs++;
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_RX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART5_CONFIG_RX_SER);
+ pru_suart_regs->CH_Config1.over_sampling = SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART5_CONFIG_RX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART5_CONFIG_RX_SER)) =
+ MCASP_SRCTL_RX_MODE;
+#endif
+ /* RX is active by default, write the dummy received data
+ * at PRU RAM addr 0x1FC to avoid memory corruption */
+ pru_suart_regs->CH_TXRXData = RX_DEFAULT_DATA_DUMP_ADDR;
+ pru_suart_regs->Reserved1 = 0;
+ /* SUART5 RX context base addr */
+ pru_suart_rx_priv = (pru_suart_rx_cntx_priv *)
+ (pu32_pru_ram_base + 0x110);
+ pru_suart_rx_priv->asp_rbuf_base = (u32)(MCASP_RBUF_BASE_ADDR +
+ (PRU_SUART5_CONFIG_RX_SER << 2));
+ pru_suart_rx_priv->asp_rsrctl_base = (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART5_CONFIG_RX_SER << 2));
+
+ /* Chanel 5 context information */
+ pru_suart_regs++;
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_RX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART6_CONFIG_RX_SER);
+ pru_suart_regs->CH_Config1.over_sampling = SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART6_CONFIG_RX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART6_CONFIG_RX_SER)) =
+ MCASP_SRCTL_RX_MODE;
+#endif
+ /* RX is active by default, write the dummy received data
+ * at PRU RAM addr 0x1FC to avoid memory corruption */
+ pru_suart_regs->CH_TXRXData = RX_DEFAULT_DATA_DUMP_ADDR;
+ pru_suart_regs->Reserved1 = 0;
+ pru_suart_rx_priv = (pru_suart_rx_cntx_priv *)
+ (pu32_pru_ram_base + 0x130);
+ pru_suart_rx_priv->asp_rbuf_base = (u32)(MCASP_RBUF_BASE_ADDR +
+ (PRU_SUART6_CONFIG_RX_SER << 2));
+ pru_suart_rx_priv->asp_rsrctl_base =
+ (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART6_CONFIG_RX_SER << 2));
+
+ /* Chanel 6 context information */
+ pru_suart_regs++;
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_RX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART7_CONFIG_RX_SER);
+ pru_suart_regs->CH_Config1.over_sampling = SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART7_CONFIG_RX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART7_CONFIG_RX_SER)) =
+ MCASP_SRCTL_RX_MODE;
+#endif
+ /* RX is active by default, write the dummy received data
+ * at PRU RAM addr 0x1FC to avoid memory corruption */
+ pru_suart_regs->CH_TXRXData = RX_DEFAULT_DATA_DUMP_ADDR;
+ pru_suart_regs->Reserved1 = 0;
+ /* SUART7 RX context base addr */
+ pru_suart_rx_priv = (pru_suart_rx_cntx_priv *)
+ (pu32_pru_ram_base + 0x150);
+ pru_suart_rx_priv->asp_rbuf_base = (u32)(MCASP_RBUF_BASE_ADDR +
+ (PRU_SUART7_CONFIG_RX_SER << 2));
+ pru_suart_rx_priv->asp_rsrctl_base = (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART7_CONFIG_RX_SER << 2));
+
+ /* Chanel 7 context information */
+ pru_suart_regs++;
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_RX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART8_CONFIG_RX_SER);
+ pru_suart_regs->CH_Config1.over_sampling =
+ SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART8_CONFIG_RX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART8_CONFIG_RX_SER)) =
+ MCASP_SRCTL_RX_MODE;
+#endif
+ /* RX is active by default, write the dummy received data at
+ * PRU RAM addr 0x1FC to avoid memory corruption */
+ pru_suart_regs->CH_TXRXData = RX_DEFAULT_DATA_DUMP_ADDR;
+ pru_suart_regs->Reserved1 = 0;
+ /* SUART8 RX context base addr */
+ pru_suart_rx_priv = (pru_suart_rx_cntx_priv *)
+ (pu32_pru_ram_base + 0x170);
+ pru_suart_rx_priv->asp_rbuf_base = (u32)(MCASP_RBUF_BASE_ADDR +
+ (PRU_SUART8_CONFIG_RX_SER << 2));
+ pru_suart_rx_priv->asp_rsrctl_base = (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART8_CONFIG_RX_SER << 2));
+
+ /* ****************** PRU1 RAM BASE ADDR ************************ */
+ pru_suart_regs = (PRU_SUART_RegsOvly)
+ (arm_iomap_pru->pru_io_addr + 0x2000);
+ pu32_pru_ram_base = (u8 *)(arm_iomap_pru->pru_io_addr + 0x2000);
+
+ /* ******************* TX PRU - 1 *********************** */
+ /* Channel 0 context information */
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_TX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART1_CONFIG_TX_SER);
+ pru_suart_regs->CH_Config1.over_sampling = SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART1_CONFIG_TX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART1_CONFIG_TX_SER)) =
+ MCASP_SRCTL_TX_MODE;
+#endif
+ pru_suart_regs->Reserved1 = 1;
+ /* SUART1 TX context base addr */
+ pru_suart_tx_priv = (pru_suart_tx_cntx_priv *)
+ (pu32_pru_ram_base + 0x0B0);
+ pru_suart_tx_priv->asp_xsrctl_base = (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART1_CONFIG_TX_SER << 2));
+ pru_suart_tx_priv->asp_xbuf_base = (u32)(MCASP_XBUF_BASE_ADDR +
+ (PRU_SUART1_CONFIG_TX_SER << 2));
+ /* SUART1 TX formatted data base addr */
+ pru_suart_tx_priv->buff_addr = 0x0090;
+
+ /* Channel 1 context information */
+ pru_suart_regs++;
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_TX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART2_CONFIG_TX_SER);
+ pru_suart_regs->CH_Config1.over_sampling = SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART2_CONFIG_TX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART2_CONFIG_TX_SER)) =
+ MCASP_SRCTL_TX_MODE;
+#endif
+ pru_suart_regs->Reserved1 = 1;
+ /* SUART2 TX context base addr */
+ pru_suart_tx_priv = (pru_suart_tx_cntx_priv *)
+ (pu32_pru_ram_base + 0x0DC);
+ pru_suart_tx_priv->asp_xsrctl_base = (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART2_CONFIG_TX_SER << 2));
+ pru_suart_tx_priv->asp_xbuf_base = (u32)(MCASP_XBUF_BASE_ADDR +
+ (PRU_SUART2_CONFIG_TX_SER << 2));
+ pru_suart_tx_priv->buff_addr = 0x00BC;
+
+ /* Channel 2 context information */
+ pru_suart_regs++;
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_TX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART3_CONFIG_TX_SER);
+ pru_suart_regs->CH_Config1.over_sampling = SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART3_CONFIG_TX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART3_CONFIG_TX_SER)) =
+ MCASP_SRCTL_TX_MODE;
+#endif
+ pru_suart_regs->Reserved1 = 1;
+ /* SUART3 TX context base addr */
+ pru_suart_tx_priv = (pru_suart_tx_cntx_priv *)
+ (pu32_pru_ram_base + 0x108);
+ pru_suart_tx_priv->asp_xsrctl_base = (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART3_CONFIG_TX_SER << 2));
+ pru_suart_tx_priv->asp_xbuf_base = (u32)(MCASP_XBUF_BASE_ADDR +
+ (PRU_SUART3_CONFIG_TX_SER << 2));
+ /* SUART3 TX formatted data base addr */
+ pru_suart_tx_priv->buff_addr = 0x00E8;
+
+ /* Channel 3 context information */
+ pru_suart_regs++;
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_TX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART4_CONFIG_TX_SER);
+ pru_suart_regs->CH_Config1.over_sampling = SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART4_CONFIG_TX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART4_CONFIG_TX_SER)) =
+ MCASP_SRCTL_TX_MODE;
+#endif
+ pru_suart_regs->Reserved1 = 1;
+ /* SUART4 TX context base addr */
+ pru_suart_tx_priv = (pru_suart_tx_cntx_priv *)
+ (pu32_pru_ram_base + 0x134);
+ pru_suart_tx_priv->asp_xsrctl_base = (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART4_CONFIG_TX_SER << 2));
+ pru_suart_tx_priv->asp_xbuf_base = (u32)(MCASP_XBUF_BASE_ADDR +
+ (PRU_SUART4_CONFIG_TX_SER << 2));
+ /* SUART4 TX formatted data base addr */
+ pru_suart_tx_priv->buff_addr = 0x0114;
+
+ /* Channel 4 context information */
+ pru_suart_regs++;
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_TX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART5_CONFIG_TX_SER);
+ pru_suart_regs->CH_Config1.over_sampling = SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART5_CONFIG_TX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART5_CONFIG_TX_SER)) =
+ MCASP_SRCTL_TX_MODE;
+#endif
+ pru_suart_regs->Reserved1 = 1;
+ /* SUART5 TX context base addr */
+ pru_suart_tx_priv = (pru_suart_tx_cntx_priv *)
+ (pu32_pru_ram_base + 0x160);
+ pru_suart_tx_priv->asp_xsrctl_base = (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART5_CONFIG_TX_SER << 2));
+ pru_suart_tx_priv->asp_xbuf_base = (u32)(MCASP_XBUF_BASE_ADDR +
+ (PRU_SUART5_CONFIG_TX_SER << 2));
+ /* SUART5 TX formatted data base addr */
+ pru_suart_tx_priv->buff_addr = 0x0140;
+
+ /* Channel 5 context information */
+ pru_suart_regs++;
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_TX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART6_CONFIG_TX_SER);
+ pru_suart_regs->CH_Config1.over_sampling = SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART6_CONFIG_TX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART6_CONFIG_TX_SER)) =
+ MCASP_SRCTL_TX_MODE;
+#endif
+ pru_suart_regs->Reserved1 = 1;
+ /* SUART6 TX context base addr */
+ pru_suart_tx_priv = (pru_suart_tx_cntx_priv *)
+ (pu32_pru_ram_base + 0x18C);
+ pru_suart_tx_priv->asp_xsrctl_base = (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART6_CONFIG_TX_SER << 2));
+ pru_suart_tx_priv->asp_xbuf_base = (u32)(MCASP_XBUF_BASE_ADDR +
+ (PRU_SUART6_CONFIG_TX_SER << 2));
+ /* SUART6 TX formatted data base addr */
+ pru_suart_tx_priv->buff_addr = 0x016C;
+
+ /* Channel 6 context information */
+ pru_suart_regs++;
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_TX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART7_CONFIG_TX_SER);
+ pru_suart_regs->CH_Config1.over_sampling = SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART7_CONFIG_TX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART7_CONFIG_TX_SER)) =
+ MCASP_SRCTL_TX_MODE;
+#endif
+ pru_suart_regs->Reserved1 = 1;
+ /* SUART7 TX context base addr */
+ pru_suart_tx_priv = (pru_suart_tx_cntx_priv *)
+ (pu32_pru_ram_base + 0x1B8);
+ pru_suart_tx_priv->asp_xsrctl_base = (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART7_CONFIG_TX_SER << 2));
+ pru_suart_tx_priv->asp_xbuf_base = (u32)(MCASP_XBUF_BASE_ADDR +
+ (PRU_SUART7_CONFIG_TX_SER << 2));
+ /* SUART7 TX formatted data base addr */
+ pru_suart_tx_priv->buff_addr = 0x0198;
+
+ /* Channel 7 context information */
+ pru_suart_regs++;
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_TX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART8_CONFIG_TX_SER);
+ pru_suart_regs->CH_Config1.over_sampling = SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART8_CONFIG_TX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART8_CONFIG_TX_SER)) =
+ MCASP_SRCTL_TX_MODE;
+#endif
+ pru_suart_regs->Reserved1 = 1;
+ /* SUART8 TX context base addr */
+ pru_suart_tx_priv = (pru_suart_tx_cntx_priv *)
+ (pu32_pru_ram_base + 0x1E4);
+ pru_suart_tx_priv->asp_xsrctl_base = (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART8_CONFIG_TX_SER << 2));
+ pru_suart_tx_priv->asp_xbuf_base = (u32)(MCASP_XBUF_BASE_ADDR +
+ (PRU_SUART8_CONFIG_TX_SER << 2));
+ /* SUART8 TX formatted data base addr */
+ pru_suart_tx_priv->buff_addr = 0x01C4;
+}
+#else
+void pru_set_ram_data(arm_pru_iomap *arm_iomap_pru)
+{
+
+ PRU_SUART_RegsOvly pru_suart_regs = (PRU_SUART_RegsOvly)
+ arm_iomap_pru->pru_io_addr;
+ u32 *pu32SrCtlAddr = (u32 *)(arm_iomap_pru->mcasp_io_addr + 0x180);
+ pru_suart_tx_cntx_priv *pru_suart_tx_priv = NULL;
+ pru_suart_rx_cntx_priv *pru_suart_rx_priv = NULL;
+ u8 *pu32_pru_ram_base = (u8 *)arm_iomap_pru->pru_io_addr;
+
+ /* ***************** UART 0 ************************ */
+ /* Channel 0 context information is Tx */
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_TX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART1_CONFIG_TX_SER);
+ pru_suart_regs->CH_Config1.over_sampling = SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART1_CONFIG_TX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART1_CONFIG_TX_SER)) =
+ MCASP_SRCTL_TX_MODE;
+#endif
+ pru_suart_regs->Reserved1 = 1;
+ /* SUART1 TX context base addr */
+ pru_suart_tx_priv = (pru_suart_tx_cntx_priv *)
+ (pu32_pru_ram_base + 0x0B0);
+ pru_suart_tx_priv->asp_xsrctl_base = (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART1_CONFIG_TX_SER << 2));
+ pru_suart_tx_priv->asp_xbuf_base = (u32)(MCASP_XBUF_BASE_ADDR +
+ (PRU_SUART1_CONFIG_TX_SER << 2));
+ /* SUART1 TX formatted data base addr */
+ pru_suart_tx_priv->buff_addr = 0x0090;
+
+ /* Channel 1 is Rx context information */
+ pru_suart_regs++;
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_RX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART1_CONFIG_RX_SER);
+ pru_suart_regs->CH_Config1.over_sampling = SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART1_CONFIG_RX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART1_CONFIG_RX_SER)) =
+ MCASP_SRCTL_RX_MODE;
+#endif
+ /* RX is active by default, write the dummy received data
+ *at PRU RAM addr 0x1FC to avoid memory corruption
+ */
+ pru_suart_regs->CH_TXRXData = RX_DEFAULT_DATA_DUMP_ADDR;
+ pru_suart_regs->Reserved1 = 0;
+ /* SUART1 RX context base addr */
+ pru_suart_rx_priv = (pru_suart_rx_cntx_priv *)
+ (pu32_pru_ram_base + 0x0C0);
+ pru_suart_rx_priv->asp_rbuf_base = (u32)(MCASP_RBUF_BASE_ADDR +
+ (PRU_SUART1_CONFIG_RX_SER << 2));
+ pru_suart_rx_priv->asp_rsrctl_base = (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART1_CONFIG_RX_SER << 2));
+
+ /* ************** UART 1 ************************ */
+ /* Channel 2 context information is Tx */
+ pru_suart_regs++;
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_TX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART2_CONFIG_TX_SER);
+ pru_suart_regs->CH_Config1.over_sampling = SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART2_CONFIG_TX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART2_CONFIG_TX_SER)) =
+ MCASP_SRCTL_TX_MODE;
+#endif
+ pru_suart_regs->Reserved1 = 1;
+ /* SUART2 TX context base addr */
+ pru_suart_tx_priv = (pru_suart_tx_cntx_priv *)
+ (pu32_pru_ram_base + 0x100);
+ pru_suart_tx_priv->asp_xsrctl_base = (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART2_CONFIG_TX_SER << 2));
+ pru_suart_tx_priv->asp_xbuf_base = (u32)(MCASP_XBUF_BASE_ADDR +
+ (PRU_SUART2_CONFIG_TX_SER << 2));
+ /* SUART2 TX formatted data base addr */
+ pru_suart_tx_priv->buff_addr = 0x00E0;
+
+ /* Channel 3 is Rx context information */
+ pru_suart_regs++;
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_RX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART2_CONFIG_RX_SER);
+ pru_suart_regs->CH_Config1.over_sampling =
+ SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART2_CONFIG_RX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART2_CONFIG_RX_SER)) =
+ MCASP_SRCTL_RX_MODE;
+#endif
+ /* RX is active by default, write the dummy received data
+ * at PRU RAM addr 0x1FC to avoid memory corruption
+ */
+ pru_suart_regs->CH_TXRXData = RX_DEFAULT_DATA_DUMP_ADDR;
+ pru_suart_regs->Reserved1 = 0;
+ /* SUART2 RX context base addr */
+ pru_suart_rx_priv = (pru_suart_rx_cntx_priv *)
+ (pu32_pru_ram_base + 0x110);
+ pru_suart_rx_priv->asp_rbuf_base = (u32)(MCASP_RBUF_BASE_ADDR +
+ (PRU_SUART2_CONFIG_RX_SER << 2));
+ pru_suart_rx_priv->asp_rsrctl_base = (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART2_CONFIG_RX_SER << 2));
+
+ /* **************** UART 2 ********************* */
+ /* Channel 4 context information is Tx */
+ pru_suart_regs++;
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_TX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART3_CONFIG_TX_SER);
+ pru_suart_regs->CH_Config1.over_sampling = SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART3_CONFIG_TX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART3_CONFIG_TX_SER)) =
+ MCASP_SRCTL_TX_MODE;
+#endif
+ pru_suart_regs->Reserved1 = 1;
+ /* SUART3 TX context base addr */
+ pru_suart_tx_priv = (pru_suart_tx_cntx_priv *)
+ (pu32_pru_ram_base + 0x150);
+ pru_suart_tx_priv->asp_xsrctl_base = (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART3_CONFIG_TX_SER << 2));
+ pru_suart_tx_priv->asp_xbuf_base = (u32)(MCASP_XBUF_BASE_ADDR +
+ (PRU_SUART3_CONFIG_TX_SER << 2));
+ pru_suart_tx_priv->buff_addr = 0x0130;
+
+ /* Channel 5 is Rx context information */
+ pru_suart_regs++;
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_RX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART3_CONFIG_RX_SER);
+ pru_suart_regs->CH_Config1.over_sampling = SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART3_CONFIG_RX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART3_CONFIG_RX_SER)) =
+ MCASP_SRCTL_RX_MODE;
+#endif
+ /* RX is active by default, write the dummy received data
+ * at PRU RAM addr 0x1FC to avoid memory corruption
+ */
+ pru_suart_regs->CH_TXRXData = RX_DEFAULT_DATA_DUMP_ADDR;
+ pru_suart_regs->Reserved1 = 0;
+ /* SUART3 RX context base addr */
+ pru_suart_rx_priv = (pru_suart_rx_cntx_priv *)
+ (pu32_pru_ram_base + 0x160);
+ pru_suart_rx_priv->asp_rbuf_base = (u32)(MCASP_RBUF_BASE_ADDR +
+ (PRU_SUART3_CONFIG_RX_SER << 2));
+ pru_suart_rx_priv->asp_rsrctl_base = (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART3_CONFIG_RX_SER << 2));
+
+ /* *********** UART 3 *********************** */
+ /* Channel 6 context information is Tx */
+ pru_suart_regs++;
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_TX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART4_CONFIG_TX_SER);
+ pru_suart_regs->CH_Config1.over_sampling = SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART4_CONFIG_TX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART4_CONFIG_TX_SER)) =
+ MCASP_SRCTL_TX_MODE;
+#endif
+ pru_suart_regs->Reserved1 = 1;
+ /* SUART4 TX context base addr */
+ pru_suart_tx_priv = (pru_suart_tx_cntx_priv *)
+ (pu32_pru_ram_base + 0x1A0);
+ pru_suart_tx_priv->asp_xsrctl_base = (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART4_CONFIG_TX_SER << 2));
+ pru_suart_tx_priv->asp_xbuf_base = (u32)(MCASP_XBUF_BASE_ADDR +
+ (PRU_SUART4_CONFIG_TX_SER << 2));
+ /* SUART4 TX formatted data base addr */
+ pru_suart_tx_priv->buff_addr = 0x0180;
+
+ /* Channel 7 is Rx context information */
+ pru_suart_regs++;
+ pru_suart_regs->CH_Ctrl.mode = SUART_CHN_RX;
+ pru_suart_regs->CH_Ctrl.serializer_num =
+ (0xF & PRU_SUART4_CONFIG_RX_SER);
+ pru_suart_regs->CH_Config1.over_sampling = SUART_DEFAULT_OVRSMPL;
+ pru_suart_regs->CH_Config2.bits_per_char = 8;
+#if (PRU_SUART4_CONFIG_RX_SER == PRU_SUART_SERIALIZER_NONE)
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_DISABLED;
+#else
+ pru_suart_regs->CH_TXRXStatus.chn_state = SUART_CHN_ENABLED;
+ *((u32 *)(pu32SrCtlAddr + PRU_SUART4_CONFIG_RX_SER)) =
+ MCASP_SRCTL_RX_MODE;
+#endif
+ /* RX is active by default, write the dummy received data
+ * at PRU RAM addr 0x1FC to avoid memory corruption
+ */
+ pru_suart_regs->CH_TXRXData = RX_DEFAULT_DATA_DUMP_ADDR;
+ pru_suart_regs->Reserved1 = 0;
+ /* SUART4 RX context base addr */
+ pru_suart_rx_priv = (pru_suart_rx_cntx_priv *)
+ (pu32_pru_ram_base + 0x1B0);
+ pru_suart_rx_priv->asp_rbuf_base = (u32)(MCASP_RBUF_BASE_ADDR +
+ (PRU_SUART4_CONFIG_RX_SER << 2));
+ pru_suart_rx_priv->asp_rsrctl_base = (u32)(MCASP_SRCTL_BASE_ADDR +
+ (PRU_SUART4_CONFIG_RX_SER << 2));
+}
+
+#endif
+
+static void pru_set_rx_tx_mode(u32 pru_mode, u32 pruNum)
+{
+
+ u32 pruOffset;
+
+ if (pruNum == PRU_NUM0) {
+ pruOffset = PRU_SUART_PRU0_RX_TX_MODE;
+ } else if (pruNum == PRU_NUM1) {
+ pruOffset = PRU_SUART_PRU1_RX_TX_MODE;
+ } else {
+ return;
+ }
+ pru_ram_write_data(pruOffset, (u8 *) &pru_mode, 1, &pru_arm_iomap);
+}
+
+static void pru_set_delay_count(u32 pru_freq)
+{
+ u32 u32delay_cnt;
+
+ if (pru_freq == 228)
+ u32delay_cnt = 5;
+ else if (pru_freq == 186)
+ u32delay_cnt = 5;
+ else
+ u32delay_cnt = 3;
+
+ /* PRU 0 */
+ pru_ram_write_data(PRU_SUART_PRU0_DELAY_OFFSET,
+ (u8 *) &u32delay_cnt, 1, &pru_arm_iomap);
+
+ /* PRU 1 */
+ pru_ram_write_data(PRU_SUART_PRU1_DELAY_OFFSET,
+ (u8 *) &u32delay_cnt, 1, &pru_arm_iomap);
+}
+
+static s32 suart_set_pru_id(u32 pru_no)
+{
+ u32 offset;
+ u16 reg_val = 0;
+
+ if (0 == pru_no)
+ offset = PRU_SUART_PRU0_ID_ADDR;
+ else if (1 == pru_no)
+ offset = PRU_SUART_PRU1_ID_ADDR;
+ else
+ return PRU_SUART_FAILURE;
+
+ pru_ram_read_data(offset, (u8 *) ®_val, 1, &pru_arm_iomap);
+ reg_val &= ~SUART_PRU_ID_MASK;
+ reg_val = pru_no;
+ pru_ram_write_data(offset, (u8 *) ®_val, 1, &pru_arm_iomap);
+
+ return PRU_SUART_SUCCESS;
+}
+
+/*
+ * suart Initialization routine
+ */
+s16 pru_softuart_init(u32 txBaudValue,
+ u32 rxBaudValue,
+ u32 oversampling,
+ u8 *pru_suart_emu_code,
+ u32 fw_size, arm_pru_iomap *arm_iomap_pru)
+{
+ u32 omapl_addr;
+ u32 u32loop;
+ s16 status = PRU_SUART_SUCCESS;
+ s16 idx;
+ s16 retval;
+
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) &&
+ (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ return PRU_SUART_FAILURE;
+ }
+
+ pru_arm_iomap.pru_io_addr = arm_iomap_pru->pru_io_addr;
+ pru_arm_iomap.mcasp_io_addr = arm_iomap_pru->mcasp_io_addr;
+ pru_arm_iomap.pFifoBufferPhysBase = arm_iomap_pru->pFifoBufferPhysBase;
+ pru_arm_iomap.pFifoBufferVirtBase = arm_iomap_pru->pFifoBufferVirtBase;
+ pru_arm_iomap.pru_clk_freq = arm_iomap_pru->pru_clk_freq;
+ omapl_addr = (u32)arm_iomap_pru->mcasp_io_addr;
+ /* Configure McASP0 */
+ suart_mcasp_config(omapl_addr, txBaudValue, rxBaudValue, oversampling,
+ arm_iomap_pru);
+ pru_enable(0, arm_iomap_pru);
+ pru_enable(1, arm_iomap_pru);
+ omapl_addr = (u32)arm_iomap_pru->pru_io_addr;
+ for (u32loop = 0; u32loop < 512; u32loop++) {
+ *(u32 *)(omapl_addr | u32loop) = 0x0;
+ *(u32 *)(omapl_addr | u32loop | 0x2000) = 0x0;
+ }
+ pru_load(PRU_NUM0, (u32 *)pru_suart_emu_code, (fw_size / sizeof(u32)),
+ arm_iomap_pru);
+ pru_load(PRU_NUM1, (u32 *)pru_suart_emu_code, (fw_size / sizeof(u32)),
+ arm_iomap_pru);
+ retval = arm_to_pru_intr_init();
+ if (-1 == retval)
+ return status;
+ pru_set_delay_count(pru_arm_iomap.pru_clk_freq);
+ suart_set_pru_id(PRU_NUM0);
+ suart_set_pru_id(PRU_NUM1);
+ pru_set_rx_tx_mode(PRU0_MODE, PRU_NUM0);
+ pru_set_rx_tx_mode(PRU1_MODE, PRU_NUM1);
+ pru_set_ram_data(arm_iomap_pru);
+ pru_run(PRU_NUM0, arm_iomap_pru);
+ pru_run(PRU_NUM1, arm_iomap_pru);
+
+ /* Initialize gUartStatuTable */
+ for (idx = 0; idx < 8; idx++) {
+ gUartStatuTable[idx] = ePRU_SUART_UART_FREE;
+ }
+
+ return status;
+}
+
+void pru_set_fifo_timeout(u32 timeout)
+{
+ pru_ram_write_data(PRU_SUART_PRU0_IDLE_TIMEOUT_OFFSET, (u8 *) &timeout,
+ 2, &pru_arm_iomap);
+ pru_ram_write_data(PRU_SUART_PRU1_IDLE_TIMEOUT_OFFSET, (u8 *) &timeout,
+ 2, &pru_arm_iomap);
+}
+
+s16 pru_softuart_deinit(void)
+{
+ u32 offset;
+ s16 s16retval = 0;
+ u32 u32value = 0;
+
+ offset = (u32)pru_arm_iomap.pru_io_addr | (PRU_INTC_STATCLRINT1 & 0xFFFF);
+ u32value = 0xFFFFFFFF;
+ s16retval = pru_ram_write_data_4byte(offset, (u32 *)&u32value, 1);
+ if (-1 == s16retval)
+ return -1;
+ offset =
+ (u32)pru_arm_iomap.pru_io_addr | (PRU_INTC_STATCLRINT0 &
+ 0xFFFF);
+ u32value = 0xFFFFFFFF;
+ s16retval = pru_ram_write_data_4byte(offset, (u32 *)&u32value, 1);
+ if (-1 == s16retval)
+ return -1;
+ pru_disable(&pru_arm_iomap);
+
+ return PRU_SUART_SUCCESS;
+}
+
+/* suart Instance open routine */
+s16 pru_softuart_open(suart_handle hSuart)
+{
+ s16 status = PRU_SUART_SUCCESS;
+
+ switch (hSuart->uartNum) {
+ case PRU_SUART_UART1:
+ if (gUartStatuTable[PRU_SUART_UART1 - 1] ==
+ ePRU_SUART_UART_IN_USE) {
+ status = SUART_UART_IN_USE;
+ return status;
+ } else {
+ hSuart->uartStatus = ePRU_SUART_UART_IN_USE;
+ hSuart->uartType = PRU_SUART1_CONFIG_DUPLEX;
+ hSuart->uartTxChannel = PRU_SUART1_CONFIG_TX_SER;
+ hSuart->uartRxChannel = PRU_SUART1_CONFIG_RX_SER;
+ gUartStatuTable[PRU_SUART_UART1 - 1] =
+ ePRU_SUART_UART_IN_USE;
+ }
+ break;
+
+ case PRU_SUART_UART2:
+ if (gUartStatuTable[PRU_SUART_UART2 - 1] ==
+ ePRU_SUART_UART_IN_USE) {
+ status = SUART_UART_IN_USE;
+ return status;
+ } else {
+
+ hSuart->uartStatus = ePRU_SUART_UART_IN_USE;
+ hSuart->uartType = PRU_SUART2_CONFIG_DUPLEX;
+ hSuart->uartTxChannel = PRU_SUART2_CONFIG_TX_SER;
+ hSuart->uartRxChannel = PRU_SUART2_CONFIG_RX_SER;
+ gUartStatuTable[PRU_SUART_UART2 - 1] =
+ ePRU_SUART_UART_IN_USE;
+ }
+ break;
+
+ case PRU_SUART_UART3:
+ if (gUartStatuTable[PRU_SUART_UART3 - 1] ==
+ ePRU_SUART_UART_IN_USE) {
+ status = SUART_UART_IN_USE;
+ return status;
+ } else {
+
+ hSuart->uartStatus = ePRU_SUART_UART_IN_USE;
+ hSuart->uartType = PRU_SUART3_CONFIG_DUPLEX;
+ hSuart->uartTxChannel = PRU_SUART3_CONFIG_TX_SER;
+ hSuart->uartRxChannel = PRU_SUART3_CONFIG_RX_SER;
+ gUartStatuTable[PRU_SUART_UART3 - 1] =
+ ePRU_SUART_UART_IN_USE;
+ }
+ break;
+
+ case PRU_SUART_UART4:
+ if (gUartStatuTable[PRU_SUART_UART4 - 1] ==
+ ePRU_SUART_UART_IN_USE) {
+ status = SUART_UART_IN_USE;
+ return status;
+ } else {
+
+ hSuart->uartStatus = ePRU_SUART_UART_IN_USE;
+ hSuart->uartType = PRU_SUART4_CONFIG_DUPLEX;
+ hSuart->uartTxChannel = PRU_SUART4_CONFIG_TX_SER;
+ hSuart->uartRxChannel = PRU_SUART4_CONFIG_RX_SER;
+
+ gUartStatuTable[PRU_SUART_UART4 - 1] =
+ ePRU_SUART_UART_IN_USE;
+ }
+ break;
+
+ case PRU_SUART_UART5:
+ if (gUartStatuTable[PRU_SUART_UART5 - 1] ==
+ ePRU_SUART_UART_IN_USE) {
+ status = SUART_UART_IN_USE;
+ return status;
+ } else {
+ hSuart->uartStatus = ePRU_SUART_UART_IN_USE;
+ hSuart->uartType = PRU_SUART5_CONFIG_DUPLEX;
+ hSuart->uartTxChannel = PRU_SUART5_CONFIG_TX_SER;
+ hSuart->uartRxChannel = PRU_SUART5_CONFIG_RX_SER;
+
+ gUartStatuTable[PRU_SUART_UART5 - 1] =
+ ePRU_SUART_UART_IN_USE;
+ }
+ break;
+
+ case PRU_SUART_UART6:
+ if (gUartStatuTable[PRU_SUART_UART6 - 1] ==
+ ePRU_SUART_UART_IN_USE) {
+ status = SUART_UART_IN_USE;
+ return status;
+ } else {
+ hSuart->uartStatus = ePRU_SUART_UART_IN_USE;
+ hSuart->uartType = PRU_SUART6_CONFIG_DUPLEX;
+ hSuart->uartTxChannel = PRU_SUART6_CONFIG_TX_SER;
+ hSuart->uartRxChannel = PRU_SUART6_CONFIG_RX_SER;
+ gUartStatuTable[PRU_SUART_UART6 - 1] =
+ ePRU_SUART_UART_IN_USE;
+ }
+ break;
+
+ case PRU_SUART_UART7:
+ if (gUartStatuTable[PRU_SUART_UART7 - 1] ==
+ ePRU_SUART_UART_IN_USE) {
+ status = SUART_UART_IN_USE;
+ return status;
+ } else {
+ hSuart->uartStatus = ePRU_SUART_UART_IN_USE;
+ hSuart->uartType = PRU_SUART7_CONFIG_DUPLEX;
+ hSuart->uartTxChannel = PRU_SUART7_CONFIG_TX_SER;
+ hSuart->uartRxChannel = PRU_SUART7_CONFIG_RX_SER;
+ gUartStatuTable[PRU_SUART_UART7 - 1] =
+ ePRU_SUART_UART_IN_USE;
+ }
+ break;
+
+ case PRU_SUART_UART8:
+ if (gUartStatuTable[PRU_SUART_UART8 - 1] ==
+ ePRU_SUART_UART_IN_USE) {
+ status = SUART_UART_IN_USE;
+ return status;
+ } else {
+ hSuart->uartStatus = ePRU_SUART_UART_IN_USE;
+ hSuart->uartType = PRU_SUART8_CONFIG_DUPLEX;
+ hSuart->uartTxChannel = PRU_SUART8_CONFIG_TX_SER;
+ hSuart->uartRxChannel = PRU_SUART8_CONFIG_RX_SER;
+ gUartStatuTable[PRU_SUART_UART8 - 1] =
+ ePRU_SUART_UART_IN_USE;
+ }
+ break;
+
+ default:
+ status = SUART_INVALID_UART_NUM;
+ break;
+ }
+ return status;
+}
+
+/* suart instance close routine */
+s16 pru_softuart_close(suart_handle hUart)
+{
+ s16 status = SUART_SUCCESS;
+
+ if (hUart == NULL) {
+ return PRU_SUART_ERR_HANDLE_INVALID;
+ } else {
+ gUartStatuTable[hUart->uartNum - 1] = ePRU_SUART_UART_FREE;
+ /* Reset the Instance to Invalid */
+ hUart->uartNum = PRU_SUART_UARTx_INVALID;
+ hUart->uartStatus = ePRU_SUART_UART_FREE;
+ }
+ return status;
+}
+
+/*
+ * suart routine for setting relative baud rate
+ */
+s16 pru_softuart_setbaud(suart_handle hUart, u16 txClkDivisor, u16 rxClkDivisor)
+{
+ u32 offset;
+ u32 pruOffset;
+ s16 status = SUART_SUCCESS;
+ u16 chNum;
+ u16 regval = 0;
+
+ if (hUart == NULL)
+ return PRU_SUART_ERR_HANDLE_INVALID;
+
+ /* Set the clock divisor value s32o the McASP */
+ if ((txClkDivisor > 385) || (txClkDivisor == 0))
+ return SUART_INVALID_CLKDIVISOR;
+ if ((rxClkDivisor > 385) || (rxClkDivisor == 0))
+ return SUART_INVALID_CLKDIVISOR;
+ chNum = hUart->uartNum - 1;
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+ || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ /* channel starts from 0 and uart instance starts from 1 */
+ chNum = (hUart->uartNum * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+ if (hUart->uartNum <= 4) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ chNum -= 8;
+ }
+ } else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+
+ if (txClkDivisor != 0) {
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CONFIG1_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®val, 2, &pru_arm_iomap);
+ regval &= (~0x3FF);
+ regval |= txClkDivisor;
+ pru_ram_write_data(offset, (u8 *) ®val, 2, &pru_arm_iomap);
+ }
+ if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ } else if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+ (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ chNum++;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+ regval = 0;
+ if (rxClkDivisor != 0) {
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CONFIG1_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®val, 2, &pru_arm_iomap);
+ regval &= (~0x3FF);
+ regval |= txClkDivisor;
+ pru_ram_write_data(offset, (u8 *) ®val, 2, &pru_arm_iomap);
+ }
+ return status;
+}
+
+/*
+ * suart routine for setting number of bits per character for a specific uart
+ */
+s16 pru_softuart_setdatabits(suart_handle hUart, u16 txDataBits, u16 rxDataBits)
+{
+ u32 offset;
+ u32 pruOffset;
+ s16 status = SUART_SUCCESS;
+ u16 chNum;
+ u32 reg_val;
+
+ if (hUart == NULL) {
+ return PRU_SUART_ERR_HANDLE_INVALID;
+ }
+
+ /*
+ * NOTE:
+ * The supported data bits are 6, 7, 8, 9, 10, 11, 12 bits per character
+ */
+
+ if ((txDataBits < ePRU_SUART_DATA_BITS6)
+ || (txDataBits > ePRU_SUART_DATA_BITS12)) {
+ return PRU_SUART_ERR_PARAMETER_INVALID;
+ }
+
+ if ((rxDataBits < ePRU_SUART_DATA_BITS6)
+ || (rxDataBits > ePRU_SUART_DATA_BITS12)) {
+ return PRU_SUART_ERR_PARAMETER_INVALID;
+ }
+
+ chNum = hUart->uartNum - 1;
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+ || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ chNum = (hUart->uartNum * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+ if (hUart->uartNum <= 4) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ chNum -= 8;
+ }
+ } else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+
+ if (txDataBits != 0) {
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CONFIG2_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®_val, 1, &pru_arm_iomap);
+ reg_val &= ~(0xF);
+ reg_val |= txDataBits;
+ pru_ram_write_data(offset, (u8 *) ®_val, 1, &pru_arm_iomap);
+ }
+ if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ } else if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+ || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ chNum++;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+ if (rxDataBits != 0) {
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CONFIG2_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®_val, 1, &pru_arm_iomap);
+ reg_val &= ~(0xF);
+ reg_val |= rxDataBits;
+ pru_ram_write_data(offset, (u8 *) &rxDataBits, 1, &pru_arm_iomap);
+ }
+
+ return status;
+}
+
+/*
+ * suart routine to configure specific uart
+ */
+s16 pru_softuart_setconfig(suart_handle hUart, suart_config *configUart)
+{
+ u32 offset;
+ u32 pruOffset;
+ s16 status = SUART_SUCCESS;
+ u16 chNum;
+ u16 regVal = 0;
+
+ if (hUart == NULL) {
+ return PRU_SUART_ERR_HANDLE_INVALID;
+ }
+
+ /*
+ * NOTE:
+ * Dependent baud rate for the given UART, the value MUST BE LESS THAN OR
+ * EQUAL TO 64, preScalarValue <= 64
+ */
+ if ((configUart->txClkDivisor > 384)
+ || (configUart->rxClkDivisor > 384)) {
+ return SUART_INVALID_CLKDIVISOR;
+ }
+ if ((configUart->txBitsPerChar < 8) || (configUart->txBitsPerChar > 14)) {
+ return PRU_SUART_ERR_PARAMETER_INVALID;
+ }
+ if ((configUart->rxBitsPerChar < 8) || (configUart->rxBitsPerChar > 14)) {
+ return PRU_SUART_ERR_PARAMETER_INVALID;
+ }
+ chNum = hUart->uartNum - 1;
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+ || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ chNum = (hUart->uartNum * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+ if (hUart->uartNum <= 4) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ chNum -= 8;
+ }
+ } else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+
+ /* Configuring the Transmit part of the given UART */
+ /* Serializer has been as TX in mcasp config, by writing 1 in bits
+ * corresponding to tx serializer in PFUNC regsiter ie already set
+ * to GPIO mode PRU code will set then back to MCASP mode once TX
+ * request for that serializer is posted.It is required because at this
+ * pos32 Mcasp is accessed by both PRU and DSP have lower priority for
+ * Mcasp in comparison to PRU and DPS keeps on looping there only
+ */
+ /*
+ * suart_mcasp_tx_serialzier_set
+ * (configUart->TXSerializer, &pru_arm_iomap);
+ */
+ /* Configuring TX serializer */
+ if (configUart->TXSerializer != PRU_SUART_SERIALIZER_NONE) {
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CTRL_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+ regVal = regVal | (configUart->TXSerializer <<
+ PRU_SUART_CH_CTRL_SR_SHIFT);
+ pru_ram_write_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CONFIG1_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+ regVal = regVal | (configUart->txClkDivisor <<
+ PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
+ pru_ram_write_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CONFIG2_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+ regVal = regVal | (configUart->txBitsPerChar <<
+ PRU_SUART_CH_CONFIG2_BITPERCHAR_SHIFT);
+ pru_ram_write_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+ offset = 8;
+ pru_softuart_write(hUart, &offset, 0);
+ }
+
+ if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ } else if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+ (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ chNum++;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+
+ /* Configuring the Transmit part of the given UART */
+ if (configUart->RXSerializer != PRU_SUART_SERIALIZER_NONE) {
+ /* Configuring RX serializer */
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CTRL_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+ regVal = regVal | (configUart->RXSerializer <<
+ PRU_SUART_CH_CTRL_SR_SHIFT);
+ pru_ram_write_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+
+ /* Configuring RX prescalar value and Oversampling */
+ offset =
+ pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CONFIG1_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+ regVal = regVal | (configUart->rxClkDivisor <<
+ PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT) |
+ (configUart->Oversampling <<
+ PRU_SUART_CH_CONFIG1_OVS_SHIFT);
+ pru_ram_write_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+
+ /* Configuring RX bits per character value */
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CONFIG2_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+ regVal = regVal | (configUart->rxBitsPerChar <<
+ PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
+ pru_ram_write_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+ }
+ return status;
+}
+
+/*
+ * suart routine for getting the number of bytes transfered
+ */
+s16 pru_softuart_getTxDataLen(suart_handle hUart)
+{
+ u32 offset;
+ u32 pruOffset;
+ u16 chNum;
+ u16 u16ReadValue = 0;
+
+ if (hUart == NULL) {
+ return PRU_SUART_ERR_HANDLE_INVALID;
+ }
+
+ chNum = hUart->uartNum - 1;
+
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+ (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ chNum = (hUart->uartNum * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+ if (hUart->uartNum <= 4) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ chNum -= 8;
+ }
+ } else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CONFIG2_OFFSET;
+ pru_ram_read_data(offset, (u8 *) &u16ReadValue, 2, &pru_arm_iomap);
+ u16ReadValue = ((u16ReadValue & PRU_SUART_CH_CONFIG1_DIVISOR_MASK) >>
+ PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
+ return u16ReadValue;
+}
+
+/*
+ * suart routine for getting the number of bytes received
+ */
+s16 pru_softuart_getRxDataLen(suart_handle hUart)
+{
+ u32 offset;
+ u32 pruOffset;
+ u16 chNum;
+ u16 u16ReadValue = 0;
+
+ if (hUart == NULL) {
+ return PRU_SUART_ERR_HANDLE_INVALID;
+ }
+ chNum = hUart->uartNum - 1;
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+ (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ chNum = (hUart->uartNum * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+ if (hUart->uartNum <= 4) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ chNum -= 8;
+ }
+ chNum++;
+ } else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CONFIG2_OFFSET;
+ pru_ram_read_data(offset, (u8 *) &u16ReadValue, 2, &pru_arm_iomap);
+ u16ReadValue = ((u16ReadValue & PRU_SUART_CH_CONFIG1_DIVISOR_MASK) >>
+ PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
+
+ return u16ReadValue;
+}
+
+/*
+ * suart routine to get the configuration information from a specific uart
+ */
+s16 pru_softuart_getconfig(suart_handle hUart, suart_config *configUart)
+{
+ u32 offset;
+ u32 pruOffset;
+ u16 chNum;
+ u16 regVal = 0;
+ s16 status = SUART_SUCCESS;
+
+ if (hUart == NULL) {
+ return PRU_SUART_ERR_HANDLE_INVALID;
+ }
+
+ /*
+ * NOTE:
+ * Dependent baud rate for the given UART, the value MUST BE LESS THAN OR
+ * EQUAL TO 64, preScalarValue <= 64
+ */
+
+ chNum = hUart->uartNum - 1;
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+ (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ /* channel starts from 0 and uart instance starts from 1 */
+ chNum = (hUart->uartNum * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+ if (hUart->uartNum <= 4) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ chNum -= 8;
+ }
+ } else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+
+ /* Configuring the Transmit part of the given UART */
+ /* Configuring TX serializer */
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CTRL_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+ configUart->TXSerializer = ((regVal & PRU_SUART_CH_CTRL_SR_MASK) >>
+ PRU_SUART_CH_CTRL_SR_SHIFT);
+ /* Configuring TX prescalar value */
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CONFIG1_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+ configUart->txClkDivisor = ((regVal & PRU_SUART_CH_CONFIG1_DIVISOR_MASK)
+ >> PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
+
+ /* Configuring TX bits per character value */
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CONFIG2_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+ configUart->txBitsPerChar = ((regVal & PRU_SUART_CH_CONFIG1_DIVISOR_MASK)
+ >> PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
+
+ if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ } else if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+ (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ chNum++;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+ /* Configuring the Transmit part of the given UART */
+ /* Configuring RX serializer */
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CTRL_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+ configUart->RXSerializer = ((regVal & PRU_SUART_CH_CTRL_SR_MASK) >>
+ PRU_SUART_CH_CTRL_SR_SHIFT);
+
+ /* Configuring RX prescalar value and Oversampling */
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CONFIG1_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+ configUart->rxClkDivisor = ((regVal & PRU_SUART_CH_CONFIG1_DIVISOR_MASK)
+ >> PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
+ configUart->Oversampling = ((regVal & PRU_SUART_CH_CONFIG1_OVS_MASK) >>
+ PRU_SUART_CH_CONFIG1_OVS_SHIFT);
+
+ /* Configuring RX bits per character value */
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CONFIG2_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+ configUart->rxBitsPerChar = ((regVal & PRU_SUART_CH_CONFIG1_DIVISOR_MASK)
+ >> PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
+
+ return status;
+}
+
+s32 pru_softuart_pending_tx_request(void)
+{
+ u32 offset = 0;
+ u32 u32ISRValue = 0;
+
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+ || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ return SUART_SUCCESS;
+ } else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+ /* Read PRU Interrupt Status Register from PRU */
+ offset = (u32)pru_arm_iomap.pru_io_addr |
+ (PRU_INTC_STATCLRINT1 & 0xFFFF);
+ pru_ram_read_data_4byte(offset, (u32 *)&u32ISRValue, 1);
+ if ((u32ISRValue & 0x1) == 0x1)
+ return PRU_SUART_FAILURE;
+ } else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+ /* Read PRU Interrupt Status Register from PRU */
+ offset = (u32)pru_arm_iomap.pru_io_addr |
+ (PRU_INTC_STATCLRINT1 & 0xFFFF);
+ pru_ram_read_data_4byte(offset, (u32 *)&u32ISRValue, 1);
+ if ((u32ISRValue & 0x2) == 0x2)
+ return PRU_SUART_FAILURE;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+
+ return SUART_SUCCESS;
+}
+
+/*
+ * suart data transmit routine
+ */
+s16 pru_softuart_write(suart_handle hUart, u32 *ptTxDataBuf, u16 dataLen)
+{
+ u32 offset = 0;
+ u32 pruOffset;
+ s16 status = SUART_SUCCESS;
+ u16 chNum;
+ u16 regVal = 0;
+ u16 pru_num;
+
+ if (hUart == NULL) {
+ return PRU_SUART_ERR_HANDLE_INVALID;
+ }
+ chNum = hUart->uartNum - 1;
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+ || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ chNum = (hUart->uartNum * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+ if (hUart->uartNum <= 4) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ pru_num = hUart->uartNum;
+ } else {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ chNum -= 8;
+ pru_num = hUart->uartNum;
+ }
+ } else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ pru_num = 0;
+ } else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ pru_num = 1;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+
+ /* Writing data length to SUART channel register */
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CONFIG2_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+ regVal &= ~PRU_SUART_CH_CONFIG2_DATALEN_MASK;
+ regVal = regVal | (dataLen << PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
+ pru_ram_write_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+
+ /* Writing the data pos32er to channel TX data pointer */
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_TXRXDATA_OFFSET;
+ pru_ram_write_data(offset, (u8 *) ptTxDataBuf, 4, &pru_arm_iomap);
+
+ /* Service Request to PRU */
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CTRL_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+ regVal &= ~(PRU_SUART_CH_CTRL_MODE_MASK | PRU_SUART_CH_CTRL_SREQ_MASK);
+ regVal |= (PRU_SUART_CH_CTRL_TX_MODE << PRU_SUART_CH_CTRL_MODE_SHIFT) |
+ (PRU_SUART_CH_CTRL_SREQ << PRU_SUART_CH_CTRL_SREQ_SHIFT);
+ pru_ram_write_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+
+ /* generate ARM->PRU event */
+ suart_arm_to_pru_intr(pru_num);
+
+ return status;
+}
+
+/*
+ * suart data receive routine
+ */
+s16 pru_softuart_read(suart_handle hUart, u32 *ptDataBuf, u16 dataLen)
+{
+ u32 offset = 0;
+ u32 pruOffset;
+ s16 status = SUART_SUCCESS;
+ u16 chNum;
+ u16 regVal = 0;
+ u16 pru_num;
+ if (hUart == NULL) {
+ return PRU_SUART_ERR_HANDLE_INVALID;
+ }
+ chNum = hUart->uartNum - 1;
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+ (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ /* channel starts from 0 and uart instance starts from 1 */
+ chNum = (hUart->uartNum * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+ if (hUart->uartNum <= 4) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ pru_num = hUart->uartNum;
+ } else {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ chNum -= 8;
+ pru_num = hUart->uartNum;
+ }
+ chNum++;
+ } else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ pru_num = 0;
+ } else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ pru_num = 1;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+ /* Writing data length to SUART channel register */
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CONFIG2_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+ regVal &= ~PRU_SUART_CH_CONFIG2_DATALEN_MASK;
+ regVal = regVal | (dataLen << PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
+ pru_ram_write_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+
+ /* Writing the data pos32er to channel RX data pointer */
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_TXRXDATA_OFFSET;
+ pru_ram_write_data(offset, (u8 *) ptDataBuf, 4, &pru_arm_iomap);
+
+ /* Service Request to PRU */
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CTRL_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+ regVal &= ~(PRU_SUART_CH_CTRL_MODE_MASK | PRU_SUART_CH_CTRL_SREQ_MASK);
+ regVal |= (PRU_SUART_CH_CTRL_RX_MODE << PRU_SUART_CH_CTRL_MODE_SHIFT) |
+ (PRU_SUART_CH_CTRL_SREQ << PRU_SUART_CH_CTRL_SREQ_SHIFT);
+ pru_ram_write_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+
+ /* enable the timeout s32errupt */
+ suart_intr_setmask(hUart->uartNum, PRU_RX_INTR, CHN_TXRX_IE_MASK_TIMEOUT);
+
+ /* generate ARM->PRU event */
+ suart_arm_to_pru_intr(pru_num);
+
+ return status;
+}
+
+/*
+ * suart routine to read the data from the RX FIFO
+ */
+s16 pru_softuart_read_data(suart_handle hUart, u8 *pDataBuffer,
+ s32 s32MaxLen, u32 *pu32DataRead)
+{
+ s16 retVal = PRU_SUART_SUCCESS;
+ u8 *pu8SrcAddr = NULL;
+ u32 u32DataRead = 0;
+ u32 u32DataLen = 0;
+ u32 u32CharLen = 0;
+ u32 offset = 0;
+ u32 pruOffset;
+ u16 chNum;
+ u16 u16Status = 0;
+
+ if (hUart == NULL) {
+ return PRU_SUART_ERR_HANDLE_INVALID;
+ }
+
+ chNum = hUart->uartNum - 1;
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+ || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ /* channel starts from 0 and uart instance starts from 1 */
+ chNum = (hUart->uartNum * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+ if (hUart->uartNum <= 4) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ chNum -= 8;
+ }
+ chNum++;
+ } else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+
+ /* Get the data pos32er from channel RX data pointer */
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_TXRXDATA_OFFSET;
+ pru_ram_read_data(offset, (u8 *) &pu8SrcAddr, 4, &pru_arm_iomap);
+
+ /* Reading data length from SUART channel register */
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CONFIG2_OFFSET;
+ pru_ram_read_data(offset, (u8 *) &u32DataLen, 2, &pru_arm_iomap);
+
+ /* read the character length */
+ u32CharLen = u32DataLen & PRU_SUART_CH_CONFIG2_BITPERCHAR_MASK;
+ u32CharLen -= 2; /* remove the START & STOP bit */
+
+ u32DataLen &= PRU_SUART_CH_CONFIG2_DATALEN_MASK;
+ u32DataLen = u32DataLen >> PRU_SUART_CH_CONFIG2_DATALEN_SHIFT;
+ u32DataLen++;
+
+ /* if the character length is greater than 8, then the size doubles */
+ if (u32CharLen > 8)
+ u32DataLen *= 2;
+
+ /* Check if the time-out had occured. If, yes, then we need to find the
+ * number of bytes read from PRU. Else, we need to
+ * read the requested bytes
+ */
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_TXRXSTATUS_OFFSET;
+ pru_ram_read_data(offset, (u8 *) &u16Status, 1, &pru_arm_iomap);
+ if (CHN_TXRX_STATUS_TIMEOUT == (u16Status & CHN_TXRX_STATUS_TIMEOUT)) {
+ /* determine the number of bytes read s32o the FIFO */
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_BYTESDONECNTR_OFFSET;
+ pru_ram_read_data(offset, (u8 *) &u32DataRead, 1, &pru_arm_iomap);
+
+ /* if the character length is greater than 8, then the size doubles */
+ if (u32CharLen > 8)
+ u32DataRead *= 2;
+
+/*
+ * the data corresponding is loaded in second
+ * half during the timeout
+ */
+ if (u32DataRead > u32DataLen) {
+ u32DataRead -= u32DataLen;
+ pu8SrcAddr += (u32DataLen + 1);
+ }
+
+ pru_softuart_clrRxFifo(hUart);
+ } else {
+ u32DataRead = u32DataLen;
+/*
+ * if the bit is set, the data is in the first
+ * half of the FIFO else the data is in the second half
+ */
+ /* Determine the buffer index by reading FIFO_OddEven flag*/
+ if (u16Status & CHN_TXRX_STATUS_CMPLT) {
+ pu8SrcAddr += u32DataLen;
+ }
+ }
+
+ /* we should be copying only max len given by the application */
+ if (u32DataRead > s32MaxLen)
+ u32DataRead = s32MaxLen;
+
+/* evaluate the virtual address of the FIFO address
+ * based on the physical addr
+ */
+ pu8SrcAddr = (u8 *)((u32) pu8SrcAddr -
+ (u32) pru_arm_iomap.pFifoBufferPhysBase +
+ (u32) pru_arm_iomap.pFifoBufferVirtBase);
+
+ /* Now we have both the data length and the source address. copy */
+ for (offset = 0; offset < u32DataRead; offset++)
+ *pDataBuffer++ = *pu8SrcAddr++;
+ *pu32DataRead = u32DataRead;
+ retVal = PRU_SUART_SUCCESS;
+
+ return retVal;
+}
+
+/*
+ * suart routine to disable the receive functionality.
+ * This routine stops the PRU from receiving on selected
+ * UART and also disables the McASP serializer corresponding
+ * to this UART Rx line.
+ */
+s16 pru_softuart_stopReceive(suart_handle hUart)
+{
+ u16 status = SUART_SUCCESS;
+ u32 offset;
+ u32 pruOffset;
+ u16 chNum;
+ u16 u16Status;
+
+ if (hUart == NULL) {
+ return PRU_SUART_ERR_HANDLE_INVALID;
+ }
+
+ chNum = hUart->uartNum - 1;
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+ || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+
+ /* channel starts from 0 and uart instance starts from 1 */
+ chNum = (hUart->uartNum * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+
+ if (hUart->uartNum <= 4) {
+ /* PRU0 */
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else {
+ /* PRU1 */
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ /* First 8 channel corresponds to PRU0 */
+ chNum -= 8;
+ }
+ chNum++;
+ } else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+
+ /* read the existing value of status flag */
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_TXRXSTATUS_OFFSET;
+ pru_ram_read_data(offset, (u8 *) &u16Status, 1, &pru_arm_iomap);
+
+ /* we need to clear the busy bit corresponding to this receive channel */
+ u16Status &= ~(CHN_TXRX_STATUS_RDY);
+ pru_ram_write_data(offset, (u8 *) &u16Status, 1, &pru_arm_iomap);
+
+ /* get the serizlizer number being used for this Rx channel */
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CTRL_OFFSET;
+ pru_ram_read_data(offset, (u8 *) &u16Status, 2, &pru_arm_iomap);
+ u16Status &= PRU_SUART_CH_CTRL_SR_MASK;
+ u16Status = u16Status >> PRU_SUART_CH_CTRL_SR_SHIFT;
+
+ /* we need to de-activate the serializer corresponding to this receive */
+ status = suart_asp_serializer_deactivate(u16Status, &pru_arm_iomap);
+
+ return status;
+
+}
+
+/*
+ * suart routine to get the tx status for a specific uart
+ */
+s16 pru_softuart_getTxStatus(suart_handle hUart)
+{
+ u32 offset;
+ u32 pruOffset;
+ u16 status = SUART_SUCCESS;
+ u16 chNum;
+
+ if (hUart == NULL) {
+ return PRU_SUART_ERR_HANDLE_INVALID;
+ }
+
+ chNum = hUart->uartNum - 1;
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+ || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ /* channel starts from 0 and uart instance starts from 1 */
+ chNum = (hUart->uartNum * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+
+ if (hUart->uartNum <= 4) {
+ /* PRU0 */
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else {
+ /* PRU1 */
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ /* First 8 channel corresponds to PRU0 */
+ chNum -= 8;
+ }
+ } else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_TXRXSTATUS_OFFSET;
+ pru_ram_read_data(offset, (u8 *) &status, 1, &pru_arm_iomap);
+ return status;
+}
+
+s16 pru_softuart_clrTxStatus(suart_handle hUart)
+{
+ u32 offset;
+ u32 pruOffset;
+ u16 status = SUART_SUCCESS;
+ u16 chNum;
+
+ if (hUart == NULL) {
+ return PRU_SUART_ERR_HANDLE_INVALID;
+ }
+
+ chNum = hUart->uartNum - 1;
+
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+ || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+
+ /* channel starts from 0 and uart instance starts from 1 */
+ chNum = (hUart->uartNum * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+
+ if (hUart->uartNum <= 4) {
+ /* PRU0 */
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else {
+ /* PRU1 */
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ /* First 8 channel corresponds to PRU0 */
+ chNum -= 8;
+ }
+ } else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_TXRXSTATUS_OFFSET;
+ pru_ram_read_data(offset, (u8 *) &status, 1, &pru_arm_iomap);
+ status &= ~(0x2);
+ pru_ram_write_data(offset, (u8 *) &status, 1, &pru_arm_iomap);
+ return status;
+}
+
+/*
+ * suart routine to get the rx status for a specific uart
+ */
+s16 pru_softuart_getRxStatus(suart_handle hUart)
+{
+ u32 offset;
+ u32 pruOffset;
+ u16 status = SUART_SUCCESS;
+ u16 chNum;
+
+ if (hUart == NULL) {
+ return PRU_SUART_ERR_HANDLE_INVALID;
+ }
+ chNum = hUart->uartNum - 1;
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+ || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ /* channel starts from 0 and uart instance starts from 1 */
+ chNum = (hUart->uartNum * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+
+ if (hUart->uartNum <= 4) {
+ /* PRU0 */
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else {
+ /* PRU1 */
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ /* First 8 channel corresponds to PRU0 */
+ chNum -= 8;
+ }
+ chNum++;
+ } else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_TXRXSTATUS_OFFSET;
+ pru_ram_read_data(offset, (u8 *) &status, 1, &pru_arm_iomap);
+ return status;
+}
+
+s16 pru_softuart_clrRxFifo(suart_handle hUart)
+{
+ u32 offset;
+ u32 pruOffset;
+ u16 status = SUART_SUCCESS;
+ u16 chNum;
+ u16 regVal;
+ u16 uartNum;
+
+ if (hUart == NULL) {
+ return PRU_SUART_ERR_HANDLE_INVALID;
+ }
+ uartNum = hUart->uartNum;
+ chNum = hUart->uartNum - 1;
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+ || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+
+ /* channel starts from 0 and uart instance starts from 1 */
+ chNum = (hUart->uartNum * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+
+ if (hUart->uartNum <= 4) {
+ /* PRU0 */
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else {
+ /* PRU1 */
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ /* First 8 channel corresponds to PRU0 */
+ chNum -= 8;
+ }
+ chNum++;
+ } else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ uartNum = 0;
+ } else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ uartNum = 1;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+
+ /* Service Request to PRU */
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CTRL_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+ regVal &= ~(PRU_SUART_CH_CTRL_MODE_MASK | PRU_SUART_CH_CTRL_SREQ_MASK);
+ regVal |= (PRU_SUART_CH_CTRL_RX_MODE << PRU_SUART_CH_CTRL_MODE_SHIFT) |
+ (PRU_SUART_CH_CTRL_SREQ << PRU_SUART_CH_CTRL_SREQ_SHIFT);
+ pru_ram_write_data(offset, (u8 *) ®Val, 2, &pru_arm_iomap);
+ suart_intr_setmask(hUart->uartNum, PRU_RX_INTR, CHN_TXRX_IE_MASK_TIMEOUT);
+
+ /* generate ARM->PRU event */
+ suart_arm_to_pru_intr(uartNum);
+
+ return status;
+}
+
+s16 pru_softuart_clrRxStatus(suart_handle hUart)
+{
+ u32 offset;
+ u32 pruOffset;
+ u16 status = SUART_SUCCESS;
+ u16 chNum;
+
+ if (hUart == NULL) {
+ return PRU_SUART_ERR_HANDLE_INVALID;
+ }
+
+ chNum = hUart->uartNum - 1;
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+ || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+
+ /* channel starts from 0 and uart instance starts from 1 */
+ chNum = (hUart->uartNum * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+
+ if (hUart->uartNum <= 4) {
+ /* PRU0 */
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else {
+ /* PRU1 */
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ /* First 8 channel corresponds to PRU0 */
+ chNum -= 8;
+ }
+ chNum++;
+ } else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ } else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+
+ offset = pruOffset + (chNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_TXRXSTATUS_OFFSET;
+ pru_ram_read_data(offset, (u8 *) &status, 1, &pru_arm_iomap);
+ status &= ~(0x3C);
+ pru_ram_write_data(offset, (u8 *) &status, 1, &pru_arm_iomap);
+ return status;
+}
+
+/*
+ * suart_s32r_status_read: Gets the Global Interrupt status register
+ * for the specified SUART.
+ * uartNum < 1 to 6 >
+ * txrxFlag < Indicates TX or RX s32errupt for the uart >
+ */
+s16 pru_softuart_get_isrstatus(u16 uartNum, u16 *txrxFlag)
+{
+ u32 offset;
+ u32 u32IntcOffset;
+ u32 chNum = 0xFF;
+ u32 regVal = 0;
+ u32 u32RegVal = 0;
+ u32 u32ISRValue = 0;
+ u32 u32AckRegVal = 0;
+ u8 pru0_mode = PRU_MODE_INVALID;
+ u8 pru1_mode = PRU_MODE_INVALID;
+ u32 u32StatInxClrRegoffset = 0;
+
+ /* initialize the status & Flag to known value */
+ *txrxFlag = 0;
+
+ u32StatInxClrRegoffset = (u32)pru_arm_iomap.pru_io_addr |
+ (PRU_INTC_STATIDXCLR & 0xFFFF);
+
+ /* Read PRU Interrupt Status Register from PRU */
+ u32IntcOffset = (u32)pru_arm_iomap.pru_io_addr |
+ (PRU_INTC_STATCLRINT1 & 0xFFFF);
+
+ pru_ram_read_data_4byte(u32IntcOffset, (u32 *)&u32ISRValue, 1);
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+ || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ /* determine if the s32errupt occured in the current UART context */
+ u32RegVal = (PRU_SUART0_TX_EVT_BIT | PRU_SUART0_RX_EVT_BIT) <<
+ ((uartNum - 1) * 2);
+
+ /* channel starts from 0 and uart instance starts from 1 */
+ chNum = uartNum * 2 - 2;
+ if (uartNum <= 4) {
+ pru0_mode = PRU_MODE_RX_TX_BOTH;
+ } else {
+ pru1_mode = PRU_MODE_RX_TX_BOTH;
+ }
+ } else {
+ chNum = uartNum - 1;
+ if ((u32ISRValue & 0x03FC) != 0) {
+ u32RegVal = 0;
+
+ offset = PRU_SUART_PRU0_RX_TX_MODE;
+ pru_ram_read_data(offset, (u8 *) &pru0_mode, 1,
+ &pru_arm_iomap);
+ u32RegVal |= 1 << (uartNum + 1);
+ if (u32ISRValue & u32RegVal) {
+ /* acknowledge the s32errupt */
+ u32AckRegVal = chNum + PRU_SUART0_TX_EVT;
+ pru_ram_write_data_4byte(u32StatInxClrRegoffset,
+ (u32 *)
+ &u32AckRegVal, 1);
+ *txrxFlag |= PRU_RX_INTR;
+ }
+ }
+ pru_ram_read_data_4byte(u32IntcOffset, (u32 *)&u32ISRValue, 1);
+ if (u32ISRValue & 0x3FC00) {
+ u32RegVal = 0;
+ offset = PRU_SUART_PRU1_RX_TX_MODE;
+ pru_ram_read_data(offset, (u8 *) &pru1_mode, 1,
+ &pru_arm_iomap);
+ u32RegVal |= 1 << (uartNum + 9);
+ if (u32ISRValue & u32RegVal) {
+ /* acknowledge the s32errupt */
+ u32AckRegVal = chNum + PRU_SUART4_TX_EVT;
+ pru_ram_write_data_4byte(u32StatInxClrRegoffset,
+ (u32 *)&u32AckRegVal, 1);
+ *txrxFlag |= PRU_TX_INTR;
+ }
+ }
+ }
+ if (u32ISRValue & u32RegVal) {
+ if ((pru0_mode == PRU_MODE_RX_TX_BOTH)
+ || (pru1_mode == PRU_MODE_RX_TX_BOTH)) {
+ /* Check if the s32errupt occured for Tx */
+ u32RegVal = PRU_SUART0_TX_EVT_BIT << ((uartNum - 1) * 2);
+ if (u32ISRValue & u32RegVal) {
+ /* s32erupt occured for TX */
+ *txrxFlag |= PRU_TX_INTR;
+ /* acknowledge the RX s32errupt */
+ u32AckRegVal = chNum + PRU_SUART0_TX_EVT;
+ pru_ram_write_data_4byte(u32StatInxClrRegoffset,
+ (u32 *)&u32AckRegVal, 1);
+ }
+
+ /* Check if the s32errupt occured for Rx */
+ u32RegVal = PRU_SUART0_RX_EVT_BIT<<((uartNum - 1) * 2);
+ if (u32ISRValue & u32RegVal) {
+ /* s32erupt occured for RX */
+ *txrxFlag |= PRU_RX_INTR;
+ chNum += 1;
+
+ /* acknowledge the RX s32errupt */
+ u32AckRegVal = chNum + PRU_SUART0_TX_EVT;
+ pru_ram_write_data_4byte(u32StatInxClrRegoffset,
+ (u32 *)&u32AckRegVal, 1);
+ }
+ }
+ regVal = SUART_SUCCESS;
+ }
+ return regVal;
+}
+
+s32 pru_intr_clr_isrstatus(u16 uartNum, u32 txrxmode)
+{
+ u32 offset;
+ u16 txrxFlag = 0;
+ u16 chnNum;
+
+ chnNum = uartNum - 1;
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+ || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ /* channel starts from 0 and uart instance starts from 1 */
+ chnNum = (uartNum * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+ if (uartNum <= 4) {
+ /* PRU0 */
+ offset = PRU_SUART_PRU0_ISR_OFFSET + 1;
+ } else {
+ /* PRU1 */
+ offset = PRU_SUART_PRU1_ISR_OFFSET + 1;
+ /* First 8 channel corresponds to PRU0 */
+ chnNum -= 8;
+ }
+ if (2 == txrxmode)
+ chnNum++;
+ } else if (PRU0_MODE == txrxmode) {
+ offset = PRU_SUART_PRU0_ISR_OFFSET + 1;
+ } else if (PRU1_MODE == txrxmode) {
+ offset = PRU_SUART_PRU1_ISR_OFFSET + 1;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+
+ pru_ram_read_data(offset, (u8 *) &txrxFlag, 1, &pru_arm_iomap);
+ txrxFlag &= ~(0x2);
+ pru_ram_write_data(offset, (u8 *) &txrxFlag, 1, &pru_arm_iomap);
+
+ return 0;
+}
+
+s16 suart_arm_to_pru_intr(u16 uartNum)
+{
+ u32 u32offset;
+ u32 u32value;
+ s16 s16retval;
+
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+ || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ if ((uartNum > 0) && (uartNum <= 4)) {
+ /* PRU0 SYS_EVT32 */
+ u32value = 0x20;
+ } else if ((uartNum > 4) && (uartNum <= 8)) {
+ /* PRU1 SYS_EVT33 */
+ u32value = 0x21;
+ } else {
+ return SUART_INVALID_UART_NUM;
+ }
+ }
+
+ if ((PRU0_MODE == PRU_MODE_RX_ONLY) || (PRU1_MODE == PRU_MODE_RX_ONLY)
+ || (PRU0_MODE == PRU_MODE_TX_ONLY)
+ || (PRU1_MODE == PRU_MODE_TX_ONLY)) {
+ if (uartNum == PRU_NUM0) {
+ /* PRU0 SYS_EVT32 */
+ u32value = 0x20;
+ }
+
+ if (uartNum == PRU_NUM1) {
+ /* PRU0 SYS_EVT33 */
+ u32value = 0x21;
+ }
+ }
+
+ u32offset = (u32)pru_arm_iomap.pru_io_addr | (PRU_INTC_STATIDXSET &
+ 0xFFFF);
+ s16retval = pru_ram_write_data_4byte(u32offset, (u32 *)&u32value, 1);
+ if (s16retval == -1) {
+ return -1;
+ }
+ return 0;
+}
+
+s16 arm_to_pru_intr_init(void)
+{
+ u32 u32offset;
+ u32 u32value;
+ u32 intOffset;
+ s16 s16retval = -1;
+#if 0
+ /* Set the MCASP Event to PRU0 as Edge Triggered */
+ u32offset =
+ (u32)pru_arm_iomap.pru_io_addr | (PRU_INTC_TYPE0 & 0xFFFF);
+ u32value = 0x80000000;
+ s16retval =
+ pru_ram_write_data_4byte(u32offset, (u32 *)&u32value, 1);
+ if (s16retval == -1)
+ return -1;
+
+#endif
+ /* Clear all the host s32errupts */
+ for (intOffset = 0; intOffset <= PRU_INTC_HOSTINTLVL_MAX; intOffset++) {
+ u32offset = (u32)pru_arm_iomap.pru_io_addr |
+ (PRU_INTC_HSTINTENIDXCLR & 0xFFFF);
+ u32value = intOffset;
+ s16retval = pru_ram_write_data_4byte(u32offset, (u32 *)&u32value, 1);
+ if (s16retval == -1)
+ return -1;
+ }
+
+ /* Enable the global s32errupt */
+ u32offset = (u32)pru_arm_iomap.pru_io_addr | (PRU_INTC_GLBLEN & 0xFFFF);
+ u32value = 0x1;
+ s16retval = pru_ram_write_data_4byte(u32offset, (u32 *)&u32value, 1);
+ if (s16retval == -1) {
+ return -1;
+ }
+
+ /* Enable the Host s32errupts for all host channels */
+ for (intOffset = 0; intOffset <= PRU_INTC_HOSTINTLVL_MAX; intOffset++) {
+ u32offset = (u32)pru_arm_iomap.pru_io_addr |
+ (PRU_INTC_HSTINTENIDXSET & 0xFFFF);
+ u32value = intOffset;
+ s16retval = pru_ram_write_data_4byte(u32offset,
+ (u32 *)&u32value, 1);
+ if (s16retval == -1) {
+ return -1;
+ }
+ }
+
+ u32offset = (u32)pru_arm_iomap.pru_io_addr | (PRU_INTC_HOSTMAP0 &
+ 0xFFFF);
+ u32value = 0x03020100;
+ s16retval = pru_ram_write_data_4byte(u32offset, (u32 *)&u32value, 1);
+ if (-1 == s16retval) {
+ return -1;
+ }
+
+ u32offset = (u32)pru_arm_iomap.pru_io_addr | (PRU_INTC_HOSTMAP1 &
+ 0xFFFF);
+ u32value = 0x07060504;
+ s16retval = pru_ram_write_data_4byte(u32offset, (u32 *)&u32value, 1);
+ if (-1 == s16retval) {
+ return -1;
+ }
+ u32offset = (u32)pru_arm_iomap.pru_io_addr | (PRU_INTC_HOSTMAP2 &
+ 0xFFFF);
+ u32value = 0x00000908;
+ s16retval =
+ pru_ram_write_data_4byte(u32offset, (u32 *)&u32value, 1);
+ if (-1 == s16retval)
+ return -1;
+
+ /* Set the channel for System s32rrupts
+ * MAP Channel 0 to SYS_EVT31
+ */
+ u32offset =
+ (u32)pru_arm_iomap.pru_io_addr | (PRU_INTC_CHANMAP7 &
+ 0xFFFF);
+ u32value = 0x0000000000;
+ s16retval =
+ pru_ram_write_data_4byte(u32offset, (u32 *)&u32value, 1);
+ if (-1 == s16retval)
+ return -1;
+
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+ || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ u32offset =
+ (u32)pru_arm_iomap.pru_io_addr | (PRU_INTC_CHANMAP8
+ & 0xFFFF);
+ u32value = 0x02020100;
+ s16retval =
+ pru_ram_write_data_4byte(u32offset,
+ (u32 *)&u32value, 1);
+ if (-1 == s16retval) {
+ return -1;
+ }
+
+ /* Sets the channel for the system s32errupt
+ * MAP channel 3 to SYS_EVT36 SUART1-Tx
+ * MAP channel 3 to SYS_EVT37 SUART1-Rx
+ * MAP channel 4 to SYS_EVT38 SUART2-Tx
+ * MAP channel 4 to SYS_EVT39 SUART2-Rx
+ */
+ u32offset = (u32)pru_arm_iomap.pru_io_addr | (PRU_INTC_CHANMAP9
+ & 0xFFFF);
+ u32value = 0x04040303;
+ s16retval = pru_ram_write_data_4byte(u32offset, (u32 *)&u32value,
+ 1);
+ if (-1 == s16retval) {
+ return -1;
+ }
+
+ /* Sets the channel for the system s32errupt
+ * MAP channel 5 to SYS_EVT40 SUART3-Tx
+ * MAP channel 5 to SYS_EVT41 SUART3-Rx
+ * MAP channel 6 to SYS_EVT42 SUART4-Tx
+ * MAP channel 6 to SYS_EVT43 SUART4-Rx
+ */
+ u32offset = (u32)pru_arm_iomap.pru_io_addr |
+ (PRU_INTC_CHANMAP10 & 0xFFFF);
+ u32value = 0x06060505;
+ s16retval = pru_ram_write_data_4byte(u32offset,
+ (u32 *)&u32value, 1);
+ if (-1 == s16retval) {
+ return -1;
+ }
+
+ /* Sets the channel for the system s32errupt
+ * MAP channel 7 to SYS_EVT44 SUART5-Tx
+ * MAP channel 7 to SYS_EVT45 SUART5-Rx
+ * MAP channel 8 to SYS_EVT46 SUART6-Tx
+ * MAP channel 8 to SYS_EVT47 SUART6-Rx
+ */
+ u32offset = (u32)pru_arm_iomap.pru_io_addr |
+ (PRU_INTC_CHANMAP11 & 0xFFFF);
+ u32value = 0x08080707;
+ s16retval = pru_ram_write_data_4byte(u32offset,
+ (u32 *)&u32value, 1);
+ if (-1 == s16retval) {
+ return -1;
+ }
+
+ /* Sets the channel for the system s32errupt
+ * MAP channel 9 to SYS_EVT48 SUART7-Tx
+ * MAP channel 9 to SYS_EVT49 SUART7-Rx
+ */
+ u32offset = (u32)pru_arm_iomap.pru_io_addr |
+ (PRU_INTC_CHANMAP12 & 0xFFFF);
+ u32value = 0x00010909;
+ s16retval = pru_ram_write_data_4byte(u32offset,
+ (u32 *)&u32value, 1);
+ if (-1 == s16retval) {
+ return -1;
+ }
+ }
+ if ((PRU0_MODE == PRU_MODE_RX_ONLY) || (PRU1_MODE == PRU_MODE_RX_ONLY)
+ || (PRU0_MODE == PRU_MODE_TX_ONLY)
+ || (PRU1_MODE == PRU_MODE_TX_ONLY)) {
+ /* Sets the channel for the system s32errupt
+ * MAP channel 0 to SYS_EVT32
+ * MAP channel 1 to SYS_EVT33
+ * MAP channel 2 to SYS_EVT34 SUART0
+ * MAP channel 3 to SYS_EVT35 SUART1
+ */
+ u32offset = (u32)pru_arm_iomap.pru_io_addr | (PRU_INTC_CHANMAP8
+ & 0xFFFF);
+ u32value = 0x03020100;
+ s16retval = pru_ram_write_data_4byte(u32offset,
+ (u32 *)&u32value, 1);
+ if (-1 == s16retval) {
+ return -1;
+ }
+
+ /* Sets the channel for the system s32errupt
+ * MAP channel 4 to SYS_EVT36 SUART2
+ * MAP channel 5 to SYS_EVT37 SUART3
+ * MAP channel 6 to SYS_EVT38 SUART4
+ * MAP channel 7 to SYS_EVT39 SUART5
+ */
+ u32offset = (u32)pru_arm_iomap.pru_io_addr | (PRU_INTC_CHANMAP9
+ & 0xFFFF);
+ u32value = 0x07060504;
+ s16retval = pru_ram_write_data_4byte(u32offset,
+ (u32 *)&u32value, 1);
+ if (-1 == s16retval) {
+ return -1;
+ }
+
+ /* Sets the channel for the system s32errupt
+ * MAP channel 8 to SYS_EVT40 SUART6
+ * MAP channel 9 to SYS_EVT41 SUART7
+ * MAP channel 2 to SYS_EVT42 SUART0
+ * MAP channel 3 to SYS_EVT43 SUART1
+ */
+ u32offset = (u32)pru_arm_iomap.pru_io_addr |
+ (PRU_INTC_CHANMAP10 & 0xFFFF);
+ u32value = 0x03020908;
+ s16retval = pru_ram_write_data_4byte(u32offset,
+ (u32 *)&u32value, 1);
+ if (-1 == s16retval) {
+ return -1;
+ }
+
+ /* Sets the channel for the system s32errupt
+ * MAP channel 4 to SYS_EVT44 SUART2
+ * MAP channel 5 to SYS_EVT45 SUART3
+ * MAP channel 6 to SYS_EVT46 SUART4
+ * MAP channel 7 to SYS_EVT47 SUART5
+ */
+ u32offset = (u32)pru_arm_iomap.pru_io_addr |
+ (PRU_INTC_CHANMAP11 & 0xFFFF);
+ u32value = 0x07060504;
+ s16retval = pru_ram_write_data_4byte(u32offset,
+ (u32 *)&u32value, 1);
+ if (-1 == s16retval) {
+ return -1;
+ }
+
+ /* Sets the channel for the system s32errupt
+ * MAP channel 8 to SYS_EVT48 SUART6
+ * MAP channel 9 to SYS_EVT49 SUART7
+ */
+ u32offset = (u32)pru_arm_iomap.pru_io_addr |
+ (PRU_INTC_CHANMAP12 & 0xFFFF);
+ u32value = 0x00010908;
+ s16retval = pru_ram_write_data_4byte(u32offset,
+ (u32 *)&u32value, 1);
+ if (-1 == s16retval) {
+ return -1;
+ }
+ }
+
+ /* Clear required set of system events
+ * and enable them using indexed register
+ */
+ for (intOffset = 0; intOffset < 18; intOffset++) {
+ u32offset = (u32)pru_arm_iomap.pru_io_addr |
+ (PRU_INTC_STATIDXCLR & 0xFFFF);
+ u32value = 32 + intOffset;
+ s16retval = pru_ram_write_data_4byte(u32offset,
+ (u32 *)&u32value, 1);
+ if (s16retval == -1)
+ return -1;
+
+ }
+ /* enable only the HOST to PRU s32errupts and let the PRU to Host events be
+ * enabled by the separate API on demand basis.
+ */
+ u32offset = (u32)pru_arm_iomap.pru_io_addr | (PRU_INTC_ENIDXSET &
+ 0xFFFF);
+ u32value = 31;
+ s16retval = pru_ram_write_data_4byte(u32offset, (u32 *)&u32value, 1);
+ if (s16retval == -1)
+ return -1;
+
+ u32offset = (u32)pru_arm_iomap.pru_io_addr | (PRU_INTC_ENIDXSET &
+ 0xFFFF);
+ u32value = 32;
+ s16retval = pru_ram_write_data_4byte(u32offset, (u32 *)&u32value, 1);
+ if (s16retval == -1)
+ return -1;
+ u32offset = (u32)pru_arm_iomap.pru_io_addr | (PRU_INTC_ENIDXSET &
+ 0xFFFF);
+ u32value = 33;
+ s16retval = pru_ram_write_data_4byte(u32offset, (u32 *)&u32value, 1);
+ if (s16retval == -1)
+ return -1;
+ u32offset = (u32)pru_arm_iomap.pru_io_addr | (PRU_INTC_ENIDXSET &
+ 0xFFFF);
+ u32value = 50;
+ s16retval = pru_ram_write_data_4byte(u32offset, (u32 *)&u32value, 1);
+ if (s16retval == -1) {
+ return -1;
+ }
+
+ /* Enable the global s32errupt */
+ u32offset = (u32)pru_arm_iomap.pru_io_addr | (PRU_INTC_GLBLEN &
+ 0xFFFF);
+ u32value = 0x1;
+ s16retval = pru_ram_write_data_4byte(u32offset, (u32 *)&u32value, 1);
+ if (s16retval == -1) {
+ return -1;
+ }
+
+ /* Enable the Host s32errupts for all host channels */
+ for (intOffset = 0; intOffset <= PRU_INTC_HOSTINTLVL_MAX; intOffset++) {
+ u32offset = (u32)pru_arm_iomap.pru_io_addr |
+ (PRU_INTC_HSTINTENIDXSET & 0xFFFF);
+ u32value = intOffset;
+ s16retval = pru_ram_write_data_4byte(u32offset,
+ (u32 *)&u32value, 1);
+ if (s16retval == -1) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+s32 suart_pru_to_host_intr_enable(u16 uartNum, u32 txrxmode, s32 s32Flag)
+{
+ s32 retVal = 0;
+ u32 u32offset;
+ u32 chnNum;
+ u32 u32value;
+ s16 s16retval = 0;
+
+ if (uartNum > 8) {
+ return SUART_INVALID_UART_NUM;
+ }
+
+ chnNum = uartNum - 1;
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+ || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ chnNum = (uartNum * 2) - 2;
+ if (2 == txrxmode) { /* Rx mode */
+ chnNum++;
+ }
+ u32value = 34 + chnNum;
+ } else if ((PRU_MODE_RX_ONLY == txrxmode)
+ && (PRU0_MODE == PRU_MODE_RX_ONLY))
+ u32value = 34 + chnNum;
+ else if ((PRU_MODE_RX_ONLY == txrxmode)
+ && (PRU1_MODE == PRU_MODE_RX_ONLY))
+ u32value = 42 + chnNum;
+ else if ((PRU_MODE_TX_ONLY == txrxmode)
+ && (PRU0_MODE == PRU_MODE_TX_ONLY))
+ u32value = 34 + chnNum;
+ else if ((PRU_MODE_TX_ONLY == txrxmode)
+ && (PRU1_MODE == PRU_MODE_TX_ONLY))
+ u32value = 42 + chnNum;
+ else
+ return -1;
+
+ if (SUART_TRUE == s32Flag) {
+ u32offset = (u32)pru_arm_iomap.pru_io_addr | (PRU_INTC_ENIDXSET
+ & 0xFFFF);
+ s16retval = pru_ram_write_data_4byte(u32offset,
+ (u32 *)&u32value, 1);
+ if (s16retval == -1) {
+ return -1;
+ }
+ } else {
+ u32offset = (u32)pru_arm_iomap.pru_io_addr | (PRU_INTC_ENIDXCLR
+ & 0xFFFF);
+ s16retval = pru_ram_write_data_4byte(u32offset,
+ (u32 *)&u32value, 1);
+ if (s16retval == -1) {
+ return -1;
+ }
+ }
+ return retVal;
+}
+
+s32 suart_intr_setmask(u16 uartNum, u32 txrxmode, u32 s32rmask)
+{
+ u32 offset;
+ u32 pruOffset;
+ u32 txrxFlag;
+ u32 regval = 0;
+ u32 chnNum;
+
+ chnNum = uartNum - 1;
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+ || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ /* channel starts from 0 and uart instance starts from 1 */
+ chnNum = (uartNum * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+
+ if ((uartNum > 0) && (uartNum <= 4)) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ offset = PRU_SUART_PRU0_IMR_OFFSET;
+ } else if ((uartNum > 4) && (uartNum <= 8)) {
+ offset = PRU_SUART_PRU1_IMR_OFFSET;
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ chnNum -= 8;
+ } else {
+ return SUART_INVALID_UART_NUM;
+ }
+ if (2 == txrxmode) { /* rx mode */
+ chnNum++;
+ }
+ } else if (PRU0_MODE == txrxmode) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ offset = PRU_SUART_PRU0_IMR_OFFSET;
+ } else if (PRU1_MODE == txrxmode) {
+ offset = PRU_SUART_PRU1_IMR_OFFSET;
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+ regval = 1 << chnNum;
+ if (CHN_TXRX_IE_MASK_CMPLT == (s32rmask & CHN_TXRX_IE_MASK_CMPLT)) {
+ pru_ram_read_data(offset, (u8 *) &txrxFlag, 2, &pru_arm_iomap);
+ txrxFlag &= ~(regval);
+ txrxFlag |= regval;
+ pru_ram_write_data(offset, (u8 *) &txrxFlag, 2, &pru_arm_iomap);
+ }
+ if ((s32rmask & SUART_GBL_INTR_ERR_MASK) == SUART_GBL_INTR_ERR_MASK) {
+ regval = 0;
+ pru_ram_read_data(offset, (u8 *) ®val, 2, &pru_arm_iomap);
+ regval &= ~(SUART_GBL_INTR_ERR_MASK);
+ regval |= (SUART_GBL_INTR_ERR_MASK);
+ pru_ram_write_data(offset, (u8 *) ®val, 2, &pru_arm_iomap);
+
+ }
+ /* Break Indicator Interrupt Masked */
+ if ((s32rmask & CHN_TXRX_IE_MASK_FE) == CHN_TXRX_IE_MASK_FE) {
+ regval = 0;
+ offset = pruOffset + (chnNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CONFIG1_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®val, 2, &pru_arm_iomap);
+ regval &= ~(CHN_TXRX_IE_MASK_FE);
+ regval |= CHN_TXRX_IE_MASK_FE;
+ pru_ram_write_data(offset, (u8 *) ®val, 2, &pru_arm_iomap);
+ }
+ /* Framing Error Interrupt Masked */
+ if (CHN_TXRX_IE_MASK_BI == (s32rmask & CHN_TXRX_IE_MASK_BI)) {
+ regval = 0;
+ offset = pruOffset + (chnNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CONFIG1_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®val, 2, &pru_arm_iomap);
+ regval &= ~(CHN_TXRX_IE_MASK_BI);
+ regval |= CHN_TXRX_IE_MASK_BI;
+ pru_ram_write_data(offset, (u8 *) ®val, 2, &pru_arm_iomap);
+ }
+ /* Timeout error Interrupt Masked */
+ if (CHN_TXRX_IE_MASK_TIMEOUT == (s32rmask & CHN_TXRX_IE_MASK_TIMEOUT)) {
+ regval = 0;
+ offset = pruOffset + (chnNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CONFIG1_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®val, 2, &pru_arm_iomap);
+ regval &= ~(CHN_TXRX_IE_MASK_TIMEOUT);
+ regval |= CHN_TXRX_IE_MASK_TIMEOUT;
+ pru_ram_write_data(offset, (u8 *) ®val, 2, &pru_arm_iomap);
+ }
+ return 0;
+}
+
+s32 suart_intr_clrmask(u16 uartNum, u32 txrxmode, u32 s32rmask)
+{
+ u32 offset;
+ u32 pruOffset;
+ u16 txrxFlag;
+ u16 regval = 0;
+ u16 chnNum;
+
+ chnNum = uartNum - 1;
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+ || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ /* channel starts from 0 and uart instance starts from 1 */
+ chnNum = (uartNum * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+ if ((uartNum > 0) && (uartNum <= 4)) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ offset = PRU_SUART_PRU0_IMR_OFFSET;
+ } else if ((uartNum > 4) && (uartNum <= 8)) {
+ /* PRU1 */
+ offset = PRU_SUART_PRU1_IMR_OFFSET;
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ /* First 8 channel corresponds to PRU0 */
+ chnNum -= 8;
+ } else {
+ return SUART_INVALID_UART_NUM;
+ }
+ if (2 == txrxmode) { /* rx mode */
+ chnNum++;
+ }
+ } else if (PRU0_MODE == txrxmode) {
+ pruOffset = PRU_SUART_PRU0_CH0_OFFSET;
+ offset = PRU_SUART_PRU0_IMR_OFFSET;
+ } else if (PRU1_MODE == txrxmode) {
+ offset = PRU_SUART_PRU1_IMR_OFFSET;
+ pruOffset = PRU_SUART_PRU1_CH0_OFFSET;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+ regval = 1 << chnNum;
+ if (CHN_TXRX_IE_MASK_CMPLT == (s32rmask & CHN_TXRX_IE_MASK_CMPLT)) {
+ pru_ram_read_data(offset, (u8 *) &txrxFlag, 2, &pru_arm_iomap);
+ txrxFlag &= ~(regval);
+ pru_ram_write_data(offset, (u8 *) &txrxFlag, 2, &pru_arm_iomap);
+ }
+
+ if ((s32rmask & SUART_GBL_INTR_ERR_MASK) == SUART_GBL_INTR_ERR_MASK) {
+ regval = 0;
+ pru_ram_read_data(offset, (u8 *) ®val, 2, &pru_arm_iomap);
+ regval &= ~(SUART_GBL_INTR_ERR_MASK);
+ pru_ram_write_data(offset, (u8 *) ®val, 2, &pru_arm_iomap);
+
+ }
+ /* Break Indicator Interrupt Masked */
+ if ((s32rmask & CHN_TXRX_IE_MASK_FE) == CHN_TXRX_IE_MASK_FE) {
+ regval = 0;
+ offset =
+ pruOffset + (chnNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CONFIG1_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®val, 2, &pru_arm_iomap);
+ regval &= ~(CHN_TXRX_IE_MASK_FE);
+ pru_ram_write_data(offset, (u8 *) ®val, 2, &pru_arm_iomap);
+ }
+ /* Framing Error Interrupt Masked */
+ if (CHN_TXRX_IE_MASK_BI == (s32rmask & CHN_TXRX_IE_MASK_BI)) {
+ regval = 0;
+ offset = pruOffset + (chnNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CONFIG1_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®val, 2, &pru_arm_iomap);
+ regval &= ~(CHN_TXRX_IE_MASK_BI);
+ pru_ram_write_data(offset, (u8 *) ®val, 2, &pru_arm_iomap);
+ }
+
+ /* Timeout error Interrupt Masked */
+ if (CHN_TXRX_IE_MASK_TIMEOUT == (s32rmask & CHN_TXRX_IE_MASK_TIMEOUT)) {
+ regval = 0;
+ offset = pruOffset + (chnNum * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+ PRU_SUART_CH_CONFIG1_OFFSET;
+ pru_ram_read_data(offset, (u8 *) ®val, 2, &pru_arm_iomap);
+ regval &= ~(CHN_TXRX_IE_MASK_TIMEOUT);
+ pru_ram_write_data(offset, (u8 *) ®val, 2, &pru_arm_iomap);
+ }
+ return 0;
+}
+
+s32 suart_intr_getmask(u16 uartNum, u32 txrxmode, u32 s32rmask)
+{
+ u16 chnNum;
+ u32 offset;
+ u16 txrxFlag;
+ u16 regval = 1;
+
+ chnNum = uartNum - 1;
+ if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+ || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+ /* channel starts from 0 and uart instance starts from 1 */
+ chnNum = (uartNum * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+
+ if ((uartNum > 0) && (uartNum <= 4)) {
+
+ offset = PRU_SUART_PRU0_IMR_OFFSET;
+ } else if ((uartNum > 4) && (uartNum <= 8)) {
+ /* PRU1 */
+ offset = PRU_SUART_PRU1_IMR_OFFSET;
+ /* First 8 channel corresponds to PRU0 */
+ chnNum -= 8;
+ } else {
+ return SUART_INVALID_UART_NUM;
+ }
+
+ if (2 == txrxmode) { /* rx mode */
+ chnNum++;
+ }
+ } else if (PRU0_MODE == txrxmode) {
+ offset = PRU_SUART_PRU0_IMR_OFFSET;
+ } else if (PRU1_MODE == txrxmode) {
+ offset = PRU_SUART_PRU1_IMR_OFFSET;
+ } else {
+ return PRU_MODE_INVALID;
+ }
+ regval = regval << chnNum;
+ pru_ram_read_data(offset, (u8 *) &txrxFlag, 2, &pru_arm_iomap);
+ txrxFlag &= regval;
+ if (0 == s32rmask) {
+ if (txrxFlag == 0)
+ return 1;
+ }
+ if (1 == s32rmask) {
+ if (txrxFlag == regval)
+ return 1;
+ }
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: Jitendra Kumar <jitendra@mistralsolutions.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef _SUART_API_H_
+#define _SUART_API_H_
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <mach/pru/pru.h>
+
+#define SINGLE_PRU 0
+#define BOTH_PRU 1
+#define PRU_ACTIVE BOTH_PRU
+
+#define SUART_NUM_OF_CHANNELS_PER_SUART 2
+#define SUART_NUM_OF_BYTES_PER_CHANNEL 16
+
+#define SUART_PASS 0
+#define SUART_SUCCESS 0
+#define SUART_FAIL 1
+#define SUART_FALSE 0
+#define SUART_TRUE 1
+
+#define PRU_TX_INTR 1
+#define PRU_RX_INTR 2
+
+#define CHN_TXRX_STATUS_TIMEOUT BIT(6)
+#define CHN_TXRX_STATUS_BI BIT(5)
+#define CHN_TXRX_STATUS_FE BIT(4)
+#define CHN_TXRX_STATUS_UNERR BIT(3)
+#define CHN_TXRX_STATUS_OVRNERR BIT(3) /* UNERR->TX & OVRNERR->RX */
+#define CHN_TXRX_STATUS_ERR BIT(2)
+#define CHN_TXRX_STATUS_CMPLT BIT(1)
+#define CHN_TXRX_STATUS_RDY BIT(0)
+
+#define CHN_TXRX_IE_MASK_TIMEOUT BIT(14)
+#define CHN_TXRX_IE_MASK_BI BIT(13)
+#define CHN_TXRX_IE_MASK_FE BIT(12)
+#define CHN_TXRX_IE_MASK_CMPLT BIT(1)
+
+#define SUART_GBL_INTR_ERR_MASK BIT(9)
+#define SUART_PRU_ID_MASK 0xFF
+
+#define SUART_FIFO_LEN 15
+#define SUART_8X_OVRSMPL 1
+#define SUART_16X_OVRSMPL 2
+#define SUART_DEFAULT_OVRSMPL SUART_8X_OVRSMPL
+
+#if (SUART_DEFAULT_OVRSMPL == SUART_16X_OVRSMPL)
+#define SUART_DEFAULT_BAUD 57600
+#else
+#define SUART_DEFAULT_BAUD 115200
+#endif
+
+#define PRU_MODE_INVALID 0x00
+#define PRU_MODE_TX_ONLY 0x1
+#define PRU_MODE_RX_ONLY 0x2
+#define PRU_MODE_RX_TX_BOTH 0x3
+
+#if (PRU_ACTIVE == BOTH_PRU)
+#define PRU0_MODE PRU_MODE_RX_ONLY
+#define PRU1_MODE PRU_MODE_TX_ONLY
+#elif (PRU_ACTIVE == SINGLE_PRU)
+#define PRU0_MODE PRU_MODE_RX_TX_BOTH
+#define PRU1_MODE PRU_MODE_INVALID
+#else
+#define PRU0_MODE PRU_MODE_INVALID
+#define PRU1_MODE PRU_MODE_INVALID
+#endif
+
+#define MCASP_XBUF_BASE_ADDR (0x01d00200)
+#define MCASP_RBUF_BASE_ADDR (0x01d00280)
+#define MCASP_SRCTL_BASE_ADDR (0x01d00180)
+
+#define MCASP_SRCTL_TX_MODE (0x000D)
+#define MCASP_SRCTL_RX_MODE (0x000E)
+
+/* Since only PRU0 can work as RX */
+#define RX_DEFAULT_DATA_DUMP_ADDR (0x00001FC)
+#define PRU_NUM_OF_CHANNELS (16)
+
+#define PRU_SUART_UART1 (1u)
+#define PRU_SUART_UART2 (2u)
+#define PRU_SUART_UART3 (3u)
+#define PRU_SUART_UART4 (4u)
+#define PRU_SUART_UART5 (5u)
+#define PRU_SUART_UART6 (6u)
+#define PRU_SUART_UART7 (7u)
+#define PRU_SUART_UART8 (8u)
+
+#define PRU_SUART_UARTx_INVALID (9u)
+
+/*
+ * This enum is used to specify the direction of the channel in UART
+ */
+typedef enum {
+ SUART_CHN_TX = 1,
+ SUART_CHN_RX = 2
+} SUART_CHN_DIR;
+
+/*
+ * This enum is used to specify the state of the channel in UART. It
+ * is either enabled or disabled.
+ */
+typedef enum {
+ SUART_CHN_DISABLED = 0,
+ SUART_CHN_ENABLED = 1
+} SUART_CHN_STATE;
+
+typedef enum {
+ ePRU_SUART_DATA_BITS6 = 8,
+ ePRU_SUART_DATA_BITS7,
+ ePRU_SUART_DATA_BITS8,
+ ePRU_SUART_DATA_BITS9,
+ ePRU_SUART_DATA_BITS10,
+ ePRU_SUART_DATA_BITS11,
+ ePRU_SUART_DATA_BITS12
+ } SUART_EN_BITSPERCHAR;
+
+typedef enum {
+ ePRU_SUART_NUM_1 = 1,
+ ePRU_SUART_NUM_2,
+ ePRU_SUART_NUM_3,
+ ePRU_SUART_NUM_4,
+ ePRU_SUART_NUM_5,
+ ePRU_SUART_NUM_6,
+ ePRU_SUART_NUM_7,
+ ePRU_SUART_NUM_8
+} SUART_EN_UARTNUM;
+
+typedef enum {
+ ePRU_SUART_HALF_TX = 1,
+ ePRU_SUART_HALF_RX,
+ ePRU_SUART_FULL_TX_RX
+} SUART_EN_UARTTYPE;
+
+typedef enum {
+ ePRU_SUART_TX_CH0 = 0,
+ ePRU_SUART_TX_CH1,
+ ePRU_SUART_TX_CH2,
+ ePRU_SUART_TX_CH3,
+ ePRU_SUART_TX_CH4,
+ ePRU_SUART_TX_CH5,
+ ePRU_SUART_TX_CH6,
+ ePRU_SUART_TX_CH7
+} SUART_EN_TXCHANNEL;
+
+typedef enum {
+ ePRU_SUART_RX_CH0 = 0,
+ ePRU_SUART_RX_CH1,
+ ePRU_SUART_RX_CH2,
+ ePRU_SUART_RX_CH3,
+ ePRU_SUART_RX_CH4,
+ ePRU_SUART_RX_CH5,
+ ePRU_SUART_RX_CH6,
+ ePRU_SUART_RX_CH7
+} SUART_EN_RXCHANNEL;
+
+typedef enum {
+ ePRU_SUART_UART_FREE = 0,
+ ePRU_SUART_UART_IN_USE
+} SUART_EN_UART_STATUS;
+
+typedef struct {
+ u16 mode:2;
+ u16 service_req:1;
+ u16 asp_id:2;
+ u16 reserved1:3;
+ u16 serializer_num:4;
+ u16 reserved2:4;
+
+} pru_suart_chn_cntrl;
+
+typedef struct {
+ u16 presacler:10;
+ u16 over_sampling:2;
+ u16 framing_mask:1;
+ u16 break_mask:1;
+ u16 timeout_mask:1;
+ u16 reserved:1;
+} pru_suart_cnh_config1;
+
+typedef struct {
+ u16 bits_per_char:4;
+ u16 reserved1:4;
+ u16 data_len:4;
+ u16 reserved:4;
+} pru_suart_chn_config2;
+
+typedef struct {
+ u16 txrx_ready:1;
+ u16 txrx_complete:1;
+ u16 txrx_error:1;
+ u16 txrx_underrun:1;
+ u16 framing_error:1;
+ u16 break_error:1;
+ u16 timeout_error:1;
+ u16 reserved:8;
+ u16 chn_state:1;
+} pru_suart_chn_status;
+
+typedef struct {
+ pru_suart_chn_cntrl CH_Ctrl;
+ pru_suart_cnh_config1 CH_Config1;
+ pru_suart_chn_config2 CH_Config2;
+ pru_suart_chn_status CH_TXRXStatus;
+ u32 CH_TXRXData;
+ u32 Reserved1;
+} pru_suart_regs, *PRU_SUART_RegsOvly;
+
+typedef struct {
+ u32 asp_xsrctl_base;
+ u32 asp_xbuf_base;
+ u16 buff_addr;
+ u8 buff_size;
+ u8 bits_loaded;
+} pru_suart_tx_cntx_priv, *ppru_suart_tx_cntx_priv;
+
+typedef struct {
+ u32 asp_rbuf_base;
+ u32 asp_rsrctl_base;
+ u32 reserved1;
+ u32 reserved2;
+ u32 reserved3;
+ u32 reserved4;
+} pru_suart_rx_cntx_priv, *ppru_suart_rx_cntx_priv;
+
+typedef struct {
+ u8 TXSerializer;
+ u8 RXSerializer;
+ u16 txClkDivisor;
+ u16 rxClkDivisor;
+ u8 txBitsPerChar;
+ u8 rxBitsPerChar;
+ u8 Oversampling;
+ u8 BIIntrMask;
+ u8 FEIntrMask;
+} suart_config;
+
+typedef struct {
+ u16 uartNum;
+ u16 uartType;
+ u16 uartTxChannel;
+ u16 uartRxChannel;
+ u16 uartStatus;
+} suart_struct_handle, *suart_handle;
+
+s16 pru_softuart_init(u32 txBaudValue, u32 rxBaudValue, u32 oversampling,
+ u8 *pru_suart_emu_code, u32 fw_size,
+ arm_pru_iomap *pru_arm_iomap1);
+
+s32 pru_intr_set_mask(u16 uartNum, u32 txrxmode, u32 intrmask);
+
+s16 pru_softuart_reset(u32 txBaudValue, u32 rxBaudValue, u32 oversampling);
+
+s16 pru_softuart_open(suart_handle hSuart);
+
+s16 pru_softuart_close(suart_handle hUart);
+
+s16 pru_softuart_setbaud(suart_handle hUart, u16 txClkDivisor,
+ u16 rxClkDivisor);
+
+s16 pru_softuart_setdatabits(suart_handle hUart, u16 txDataBits,
+ u16 rxDataBits);
+
+s16 pru_softuart_setconfig(suart_handle hUart, suart_config *configUart);
+
+s16 pru_softuart_getconfig(suart_handle hUart, suart_config *configUart);
+
+s32 pru_softuart_pending_tx_request(void);
+
+s16 pru_softuart_write(suart_handle hUart, u32 *ptTxDataBuf, u16 dataLen);
+
+s16 pru_softuart_read(suart_handle hUart, u32 *ptDataBuf, u16 dataLen);
+
+s32 suart_intr_clrmask(u16 uartNum, u32 txrxmode, u32 intrmask);
+
+s16 pru_softuart_clrTxStatus(suart_handle hUart);
+
+s16 pru_softuart_getTxStatus(suart_handle hUart);
+
+s16 pru_softuart_clrRxStatus(suart_handle hUart);
+
+s16 pru_softuart_getRxStatus(suart_handle hUart);
+
+s16 pru_softuart_get_isrstatus(u16 uartNum, u16 *txrxFlag);
+
+s32 pru_intr_clr_isrstatus(u16 uartNum, u32 txrxmode);
+
+s32 suart_intr_getmask(u16 uartNum, u32 txrxmode, u32 intrmask);
+
+s32 suart_intr_setmask(u16 uartNum, u32 txrxmode, u32 intrmask);
+
+s16 pru_softuart_getTxDataLen(suart_handle hUart);
+
+s16 pru_softuart_getRxDataLen(suart_handle hUart);
+
+s16 suart_arm_to_pru_intr(u16 uartNum);
+
+s16 arm_to_pru_intr_init(void);
+
+s16 pru_softuart_deinit(void);
+
+s16 pru_softuart_clrRxFifo(suart_handle hUart);
+
+s16 pru_softuart_read_data(suart_handle hUart, u8 *pDataBuffer,
+ s32 s32MaxLen, u32 *pu32DataRead);
+
+s16 pru_softuart_stopReceive(suart_handle hUart);
+
+s32 suart_pru_to_host_intr_enable(u16 uartNum, u32 txrxmode, s32 s32Flag);
+
+void pru_set_fifo_timeout(u32 timeout);
+#endif
new file mode 100644
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: jitendra@mistralsolutions.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef _SUART_ERR_H_
+#define _SUART_ERR_H_
+
+#define PRU_SUART_SUCCESS (0u)
+#define PRU_SUART_FAILURE (-1)
+
+#define PRU_SUART_ERR_DEVICE_NOT_OPEN (1u)
+#define PRU_SUART_ERR_UARTS_INIT_FAIL (2u)
+#define PRU_SUART_ERR_UARTS_RESET_FAIL (3u)
+#define PRU_SUART_ERR_HANDLE_INVALID (4u)
+#define PRU_SUART_ERR_PARAMETER_INVALID (5u)
+
+#define PRU_SUART_ERR_TX (6u)
+#define PRU_SUART_TX_COMPLETE (7u)
+#define PRU_SUART_TX_BUSY (8u)
+#define PRU_SUART_TX_UNDERRUN (9u)
+
+#define PRU_SUART_ERR_RX (10u)
+#define PRU_SUART_RX_COMPLETE (11u)
+#define PRU_SUART_RX_BUSY (12u)
+#define PRU_SUART_RX_OVERRUN (13u)
+
+/* API Specific Errors */
+#define SUART_INVALID_TX_BAUD (14u)
+#define SUART_INVALID_OVERSAMPLING (15u)
+#define SUART_INVALID_RX_BAUD (16u)
+
+#define SUART_UART_IN_USE (17u)
+
+#define SUART_INVALID_CLKDIVISOR (18u)
+#define SUART_INVALID_UART_NUM (19u)
+#define SUART_INVALID_SR_NUM (20u)
+
+#endif
new file mode 100644
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: jitendra@mistralsolutions.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef _SUART_PRU_REGS_H_
+#define _SUART_PRU_REGS_H_
+
+#include <linux/types.h>
+
+#define PRU_DATARAM_BASE_ADDR (0x01C30000u)
+#define PRU0_DATARAM0_OFFSET (0x0000u)
+/** PRU0 DATA RAM base address */
+#define PRU0_DATARAM1_OFFSET (0x2000u)
+/** PRU0 DATA RAM base address */
+#define PRU_SUART_DATARAM0_BASE (PRU_DATARAM_BASE_ADDR + PRU0_DATARAM0_OFFSET)
+/** PRU1 DATA RAM base address */
+#define PRU_SUART_DATARAM1_BASE (PRU_DATARAM_BASE_ADDR + PRU0_DATARAM0_OFFSET)
+/** PRU1 DATA RAM base address */
+#define PRU_SUART_PRU0_CH0_OFFSET (0x0000)
+#define PRU_SUART_PRU0_CH1_OFFSET (0x0010)
+#define PRU_SUART_PRU0_CH2_OFFSET (0x0020)
+#define PRU_SUART_PRU0_CH3_OFFSET (0x0030)
+#define PRU_SUART_PRU0_CH4_OFFSET (0x0040)
+#define PRU_SUART_PRU0_CH5_OFFSET (0x0050)
+#define PRU_SUART_PRU0_CH6_OFFSET (0x0060)
+#define PRU_SUART_PRU0_CH7_OFFSET (0x0070)
+#define PRU_SUART_PRU0_IMR_OFFSET (0x0080)
+/** Interrupt Mask Register */
+#define PRU_SUART_PRU0_ISR_OFFSET (0x0082)
+/** Interrupt Status Register */
+#define PRU_SUART_PRU0_ID_ADDR (0x0084)
+/** PRU ID Register */
+#define PRU_SUART_PRU0_RX_TX_MODE (0x0085)
+#define PRU_SUART_PRU0_DELAY_OFFSET (0x0086)
+#define PRU_SUART_PRU0_IDLE_TIMEOUT_OFFSET (0x0088)
+
+/* ********* PRU 1 Macros ************* */
+#define PRU_SUART_PRU1_CH0_OFFSET (0x2000)
+#define PRU_SUART_PRU1_CH1_OFFSET (0x2010)
+#define PRU_SUART_PRU1_CH2_OFFSET (0x2020)
+#define PRU_SUART_PRU1_CH3_OFFSET (0x2030)
+#define PRU_SUART_PRU1_CH4_OFFSET (0x2040)
+#define PRU_SUART_PRU1_CH5_OFFSET (0x2050)
+#define PRU_SUART_PRU1_CH6_OFFSET (0x2060)
+#define PRU_SUART_PRU1_CH7_OFFSET (0x2070)
+#define PRU_SUART_PRU1_IMR_OFFSET (0x2080)
+#define PRU_SUART_PRU1_ISR_OFFSET (0x2082)
+#define PRU_SUART_PRU1_ID_ADDR (0x2084)
+#define PRU_SUART_PRU1_RX_TX_MODE (0x2085)
+#define PRU_SUART_PRU1_DELAY_OFFSET (0x2086)
+#define PRU_SUART_PRU1_IDLE_TIMEOUT_OFFSET (0x2088)
+
+/* SUART Channel Control Register bit descriptions */
+#define PRU_SUART_CH_CTRL_MODE_SHIFT 0x0000
+#define PRU_SUART_CH_CTRL_MODE_MASK 0x0003
+#define PRU_SUART_CH_CTRL_TX_MODE 0x0001
+#define PRU_SUART_CH_CTRL_RX_MODE 0x0002
+
+/* Service Request */
+#define PRU_SUART_CH_CTRL_SREQ_SHIFT 0x0002
+#define PRU_SUART_CH_CTRL_SREQ_MASK 0x0004
+#define PRU_SUART_CH_CTRL_SREQ 0x0001
+
+/* McASP Instance */
+#define PRU_SUART_CH_CTRL_MCASP_SHIFT 0x0003
+#define PRU_SUART_CH_CTRL_MCASP_MASK 0x0018
+#define PRU_SUART_CH_CTRL_SR_SHIFT 0x0008
+#define PRU_SUART_CH_CTRL_SR_MASK 0x0F00
+
+/* SUART channel configuration1 register descriptions */
+
+/* clock divisor - relative baud value */
+#define PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT 0x0000
+#define PRU_SUART_CH_CONFIG1_DIVISOR_MASK 0x03FF
+/* oversampling */
+#define PRU_SUART_CH_CONFIG1_OVS_SHIFT 0x000A
+#define PRU_SUART_CH_CONFIG1_OVS_MASK 0x0C00
+
+/* SUART channel configuration2 register descriptions */
+/* Bits per character */
+#define PRU_SUART_CH_CONFIG2_BITPERCHAR_SHIFT 0x0000
+#define PRU_SUART_CH_CONFIG2_BITPERCHAR_MASK 0x000F
+
+/* Bits per character */
+#define PRU_SUART_CH_CONFIG2_DATALEN_SHIFT 0x0008
+#define PRU_SUART_CH_CONFIG2_DATALEN_MASK 0x0F00
+
+/* SUART Channel register offsets */
+#define PRU_SUART_CH_CTRL_OFFSET 0x00
+#define PRU_SUART_CH_CONFIG1_OFFSET 0x02
+#define PRU_SUART_CH_CONFIG2_OFFSET 0x04
+#define PRU_SUART_CH_TXRXSTATUS_OFFSET 0x06
+#define PRU_SUART_CH_TXRXDATA_OFFSET 0x08
+#define PRU_SUART_CH_BYTESDONECNTR_OFFSET 0x0C
+
+/* SUART Event Numbers macros */
+#define PRU_SUART0_TX_EVT 34
+#define PRU_SUART0_RX_EVT 35
+#define PRU_SUART1_TX_EVT 36
+#define PRU_SUART1_RX_EVT 37
+#define PRU_SUART2_TX_EVT 38
+#define PRU_SUART2_RX_EVT 39
+#define PRU_SUART3_TX_EVT 40
+#define PRU_SUART3_RX_EVT 41
+#define PRU_SUART4_TX_EVT 42
+#define PRU_SUART4_RX_EVT 43
+#define PRU_SUART5_TX_EVT 44
+#define PRU_SUART5_RX_EVT 45
+#define PRU_SUART6_TX_EVT 46
+#define PRU_SUART6_RX_EVT 47
+#define PRU_SUART7_TX_EVT 48
+#define PRU_SUART7_RX_EVT 49
+
+#define PRU_SUART0_TX_EVT_BIT BIT(2)
+#define PRU_SUART0_RX_EVT_BIT BIT(3)
+#define PRU_SUART1_TX_EVT_BIT BIT(4)
+#define PRU_SUART1_RX_EVT_BIT BIT(5)
+#define PRU_SUART2_TX_EVT_BIT BIT(6)
+#define PRU_SUART2_RX_EVT_BIT BIT(7)
+#define PRU_SUART3_TX_EVT_BIT BIT(8)
+#define PRU_SUART3_RX_EVT_BIT BIT(9)
+#define PRU_SUART4_TX_EVT_BIT BIT(10)
+#define PRU_SUART4_RX_EVT_BIT BIT(11)
+#define PRU_SUART5_TX_EVT_BIT BIT(12)
+#define PRU_SUART5_RX_EVT_BIT BIT(13)
+#define PRU_SUART6_TX_EVT_BIT BIT(14)
+#define PRU_SUART6_RX_EVT_BIT BIT(15)
+#define PRU_SUART7_TX_EVT_BIT BIT(16)
+#define PRU_SUART7_RX_EVT_BIT BIT(17)
+
+/*
+ * SUART Config regs
+ */
+typedef struct {
+ unsigned short CHn_Ctrl;
+ unsigned short CHn_Config1;
+ unsigned short CHn_Config2;
+ unsigned short CHn_TXRXStatus;
+ unsigned int CHn_TXRXData;
+} suart_struct_pru_regs;
+
+#endif
new file mode 100644
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: Jitendra Kumar <jitendra@mistralsolutions.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <mach/pru/pru.h>
+#include <mach/pru/omapl_mcasp.h>
+#include "suart_pru_regs.h"
+#include "omapl_suart_board.h"
+#include "suart_api.h"
+#include "suart_utils.h"
+#include "suart_err.h"
+
+#define SUART_TRX_DIV_CONF_SZ 4
+
+static s16 suart_mcasp_tx_baud_set(u32 txBaudValue,
+ arm_pru_iomap *pru_arm_iomap);
+static s16 suart_mcasp_rx_baud_set(u32 rxBaudValue, u32 oversampling,
+ arm_pru_iomap *pru_arm_iomap);
+
+/*
+ * Lookup table for TX baud rate
+ * The divisor value is calculated using the formula
+ *
+ * ACLKX = (AUXCLK)/(CLKXDIV * HCLKXDIV)
+ *
+ * Where
+ * CLKXDIV takes values from 1-32
+ * HCLKXDIV takes values from 1-4096
+ * Here
+ * AUXCLK = 24MHz
+ */
+u32 lt_tx_baud_rate[][SUART_TRX_DIV_CONF_SZ] = {
+ /*BaudRate, Divisor, CLKXDIV,HCLKXDIV */
+ {300, 80000, 24, 3200},
+ {600, 40000, 15, 2500},
+ {1800, 13333, 10, 1212},
+ {2400, 10000, 4, 2000},
+ {4800, 5000, 1, 2500},
+ {7200, 3333, 0, 3333},
+ {9600, 2500, 0, 2500},
+ {14400, 1666, 0, 1666},
+ {19200, 1250, 0, 1250},
+ {38400, 625, 0, 625},
+ {57600, 416, 0, 416},
+ {115200, 208, 0, 208},
+ {230400, 104, 0, 104}
+};
+
+/*
+ * Lookup table for RX baud rate for 8 bit oversampling
+ * The divisor value is calculated using the formula
+ *
+ * ACLKR = (AUXCLK)/(CLKRDIV * HCLKRDIV) * Oversampling
+ *
+ * Where
+ * CLKRDIV takes values from 1-32
+ * HCLKRDIV takes values from 1-4096
+ * Here
+ * AUXCLK = 24MHz
+ */
+u32 lt_rx_8x_baud_rate[][SUART_TRX_DIV_CONF_SZ] = {
+/* BaudRate, Divisor, CLKXDIV, HCLKXDIV */
+ {300, 10000, 4, 2000},
+ {600, 5000, 1, 2500},
+ {1800, 1667, 0, 1667},
+ {2400, 1250, 0, 1250},
+ {7200, 417, 0, 417},
+ {4800, 625, 0, 625},
+ {9600, 312, 0, 312},
+ {14400, 208, 0, 208},
+ {19200, 156, 0, 156},
+ {38400, 78, 0, 78},
+ {57600, 52, 0, 52},
+ {115200, 26, 0, 26},
+ {230400, 13, 0, 13}
+};
+
+/*
+ * Lookup table for RX baud rate for 16 bit oversampling
+ * The divisor value is calculated using the formula
+ *
+ * ACLKR = (AUXCLK)/(CLKRDIV * HCLKRDIV) * Oversampling
+ *
+ * Where
+ * CLKRDIV takes values from 1-32
+ * HCLKRDIV takes values from 1-4096
+ * Here
+ * AUXCLK = 24MHz
+ */
+u32 lt_rx_16x_baud_rate[][SUART_TRX_DIV_CONF_SZ] = {
+/*BaudRate, Divisor, CLKXDIV, HCLKXDIV */
+ {300, 5000, 1, 2500},
+ {600, 2500, 0, 2500},
+ {1800, 833, 0, 833},
+ {2400, 625, 0, 625},
+ {4800, 312, 0, 312},
+ {7200, 208, 0, 208},
+ {9600, 156, 0, 156},
+ {14400, 104, 0, 104},
+ {19200, 78, 0, 78},
+ {38400, 39, 0, 39},
+ {57600, 26, 0, 26},
+ {115200, 13, 0, 13},
+ {230400, 6, 0, 6}
+};
+
+/*
+ * McASP configuration routine
+ */
+void suart_mcasp_config(u32 mcasp_addr,
+ u32 txBaudValue,
+ u32 rxBaudValue,
+ u32 oversampling,
+ arm_pru_iomap *pru_arm_iomap)
+{
+ OMAPL_McaspRegsOvly mcasp0Regs = (OMAPL_McaspRegsOvly) mcasp_addr;
+
+ /* reset mcasp */
+ mcasp0Regs->GBLCTL = 0;
+ mcasp0Regs->RGBLCTL = 0;
+ mcasp0Regs->XGBLCTL = 0;
+
+ /* configure receive registers */
+ if ((SUART_8X_OVRSMPL == oversampling) || (0 == oversampling)) {
+ mcasp0Regs->RMASK = 0x000000FF;
+ mcasp0Regs->RFMT = 0x0000A038; /* slot size 8 bits,RPAD=1 */
+ }
+ if (SUART_16X_OVRSMPL == oversampling) {
+ mcasp0Regs->RMASK = 0x0000FFFF;
+ mcasp0Regs->RFMT = 0x0000A078;
+ }
+
+ mcasp0Regs->AFSRCTL = 0x00000002; /* burst mode */
+ mcasp0Regs->ACLKRCTL = 0x000000A0;
+ mcasp0Regs->AHCLKRCTL = 0x00008000;
+ suart_mcasp_rx_baud_set(rxBaudValue, oversampling, pru_arm_iomap);
+
+ mcasp0Regs->RTDM = 0x00000001;
+ mcasp0Regs->RINTCTL = 0x00000002;
+ mcasp0Regs->RCLKCHK = 0x00FF0008;
+
+ /* configure transmit registers. */
+ mcasp0Regs->XMASK = 0x0000FFFF;
+ mcasp0Regs->XFMT = 0x00002078;
+ mcasp0Regs->AFSXCTL = 0x0000002; /* Burst mode */
+ mcasp0Regs->ACLKXCTL = 0x000000E0;
+ mcasp0Regs->AHCLKXCTL = 0x00008000;
+
+ suart_mcasp_tx_baud_set(txBaudValue, pru_arm_iomap);
+
+ mcasp0Regs->XTDM = 0x00000001;
+ mcasp0Regs->XINTCTL = 0x00000002;
+ mcasp0Regs->XCLKCHK = 0x00FF0008;
+
+ /* Serializer as a transmitter */
+ mcasp0Regs->SRCTL0 = 0x000c;
+ mcasp0Regs->SRCTL1 = 0x000c;
+ mcasp0Regs->SRCTL2 = 0x000c;
+ mcasp0Regs->SRCTL3 = 0x000c;
+ mcasp0Regs->SRCTL4 = 0x000c;
+ mcasp0Regs->SRCTL5 = 0x000c;
+ mcasp0Regs->SRCTL6 = 0x000c;
+ mcasp0Regs->SRCTL7 = 0x000c;
+ mcasp0Regs->SRCTL8 = 0x000c;
+ mcasp0Regs->SRCTL9 = 0x000c;
+ mcasp0Regs->SRCTL10 = 0x000c;
+ mcasp0Regs->SRCTL11 = 0x000c;
+ mcasp0Regs->SRCTL12 = 0x000c;
+ mcasp0Regs->SRCTL13 = 0x000c;
+ mcasp0Regs->SRCTL14 = 0x000c;
+ mcasp0Regs->SRCTL15 = 0x000c;
+
+ /* Configure all AXR[n] as McASP pins */
+
+ /*
+ * Setting all TX MCASP AXR[n] Pin mapped to Even Serializer number
+ * (0,2,4,6,8,10,12,14) to GPIO Mode by default. During setting the
+ * serializer to TX mode in PRU assembly code, the MCASP AXR[n] Pin
+ * would get configured to MCASP mode of operation,
+ * before Actual Data Transfer
+ */
+
+ /* Setting all TX Pin to GPIO Mode by default */
+ mcasp0Regs->PFUNC = (OMAPL_MCASP_PFUNC_RESETVAL) |
+ (1 << PRU_SUART1_CONFIG_TX_SER) | (1 << PRU_SUART2_CONFIG_TX_SER) |
+ (1 << PRU_SUART3_CONFIG_TX_SER) | (1 << PRU_SUART4_CONFIG_TX_SER) |
+ (1 << PRU_SUART5_CONFIG_TX_SER) | (1 << PRU_SUART6_CONFIG_TX_SER) |
+ (1 << PRU_SUART7_CONFIG_TX_SER) | (1 << PRU_SUART8_CONFIG_TX_SER);
+
+ mcasp0Regs->PDOUT = 0xFFFF;
+
+ /* config pin function and direction */
+ mcasp0Regs->PDIR = 0x00000000;
+ mcasp0Regs->PDIR =
+ (1 << PRU_SUART1_CONFIG_TX_SER) | (1 << PRU_SUART2_CONFIG_TX_SER) |
+ (1 << PRU_SUART3_CONFIG_TX_SER) | (1 << PRU_SUART4_CONFIG_TX_SER) |
+ (1 << PRU_SUART5_CONFIG_TX_SER) | (1 << PRU_SUART6_CONFIG_TX_SER) |
+ (1 << PRU_SUART7_CONFIG_TX_SER) | (1 << PRU_SUART8_CONFIG_TX_SER) |
+ (MCASP_PDIR_VAL);
+
+ mcasp0Regs->PDOUT = 0xFFFF;
+
+ mcasp0Regs->DITCTL = 0x00000000;
+ mcasp0Regs->DLBCTL = 0x00000000;
+ mcasp0Regs->AMUTE = 0x00000000;
+
+ mcasp0Regs->XSTAT = 0x0000FFFF; /* Clear all */
+ mcasp0Regs->RSTAT = 0x0000FFFF; /* Clear all */
+}
+
+void suart_mcasp_tx_serialzier_set(u32 serializerNum,
+ arm_pru_iomap *pru_arm_iomap)
+{
+ OMAPL_McaspRegsOvly mcasp0Regs =
+ (OMAPL_McaspRegsOvly) pru_arm_iomap->mcasp_io_addr;
+
+ mcasp0Regs->PFUNC |= (0x1 << serializerNum);
+}
+
+/*
+ * mcasp TX buard rate setting routine
+ */
+s16 suart_mcasp_tx_baud_set(u32 txBaudValue,
+ arm_pru_iomap *pru_arm_iomap)
+{
+ u32 clkDivVal;
+ u32 loopCnt;
+ s16 status = SUART_SUCCESS;
+ s16 foundVal = SUART_FALSE;
+
+ OMAPL_McaspRegsOvly mcasp0Regs =
+ (OMAPL_McaspRegsOvly) pru_arm_iomap->mcasp_io_addr;
+
+ /* Search the supported baud rate in the table */
+ for (loopCnt = 0; loopCnt < SUART_NUM_OF_BAUDS_SUPPORTED; loopCnt++) {
+ if (txBaudValue == lt_tx_baud_rate[loopCnt][0]) {
+ foundVal = SUART_TRUE;
+ break;
+ }
+ }
+ if (foundVal == SUART_TRUE) {
+ clkDivVal = lt_tx_baud_rate[loopCnt][2];
+
+ mcasp0Regs->ACLKXCTL |=
+ clkDivVal << OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT;
+ clkDivVal = lt_tx_baud_rate[loopCnt][3]; /* starts from 0 */
+ mcasp0Regs->AHCLKXCTL |=
+ clkDivVal << OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT;
+ } else {
+ return SUART_INVALID_TX_BAUD;
+ }
+ return status;
+}
+
+/*
+ * mcasp RX buard rate setting routine
+ */
+s16 suart_mcasp_rx_baud_set(u32 rxBaudValue,
+ u32 oversampling, arm_pru_iomap *pru_arm_iomap)
+{
+ u32 clkDivVal;
+ u32 loopCnt;
+ s16 status = SUART_SUCCESS;
+ s16 foundVal = SUART_FALSE;
+
+ OMAPL_McaspRegsOvly mcasp0Regs =
+ (OMAPL_McaspRegsOvly) pru_arm_iomap->mcasp_io_addr;
+
+ if (oversampling == SUART_8X_OVRSMPL) {
+ for (loopCnt = 0; loopCnt < SUART_NUM_OF_BAUDS_SUPPORTED;
+ loopCnt++) {
+ if (rxBaudValue == lt_rx_8x_baud_rate[loopCnt][0]) {
+ clkDivVal = lt_rx_8x_baud_rate[loopCnt][2];
+ mcasp0Regs->ACLKRCTL |= clkDivVal <<
+ OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT;
+ clkDivVal = lt_rx_8x_baud_rate[loopCnt][3] - 1;
+ mcasp0Regs->AHCLKRCTL |= clkDivVal <<
+ OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT;
+ foundVal = SUART_TRUE;
+ break;
+ }
+ }
+ } else if (oversampling == SUART_16X_OVRSMPL) {
+ for (loopCnt = 0; loopCnt < SUART_NUM_OF_BAUDS_SUPPORTED;
+ loopCnt++) {
+ if (rxBaudValue == lt_rx_16x_baud_rate[loopCnt][0]) {
+ clkDivVal = lt_rx_16x_baud_rate[loopCnt][2];
+ mcasp0Regs->ACLKRCTL |= clkDivVal <<
+ OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT;
+ clkDivVal = lt_rx_16x_baud_rate[loopCnt][3];
+ mcasp0Regs->AHCLKRCTL |= clkDivVal <<
+ OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT;
+ foundVal = SUART_TRUE;
+ break;
+ }
+ }
+ } else if (oversampling == 0) {
+ for (loopCnt = 0; loopCnt < SUART_NUM_OF_BAUDS_SUPPORTED;
+ loopCnt++) {
+ if (rxBaudValue == lt_tx_baud_rate[loopCnt][0]) {
+ clkDivVal = lt_tx_baud_rate[loopCnt][2];
+ mcasp0Regs->ACLKRCTL |= clkDivVal <<
+ OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT;
+ clkDivVal = lt_tx_baud_rate[loopCnt][3];
+ mcasp0Regs->AHCLKRCTL |= clkDivVal <<
+ OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT;
+ foundVal = SUART_TRUE;
+ break;
+ }
+ }
+ } else {
+ return SUART_INVALID_OVERSAMPLING;
+ }
+
+ if (foundVal != SUART_TRUE) {
+ return SUART_INVALID_RX_BAUD;
+ }
+ return status;
+}
+
+/*
+ * mcasp buard rate setting routine
+ */
+s16 suart_asp_baud_set(u32 txBaudValue, u32 rxBaudValue, u32 oversampling,
+ arm_pru_iomap *pru_arm_iomap)
+{
+ s16 status = SUART_SUCCESS;
+
+ status = suart_mcasp_tx_baud_set(txBaudValue, pru_arm_iomap);
+ status = suart_mcasp_rx_baud_set(rxBaudValue, oversampling,
+ pru_arm_iomap);
+
+ return status;
+}
+
+/*
+ * mcasp deactivate the selected serializer
+ */
+s16 suart_asp_serializer_deactivate(u16 u16srNum, arm_pru_iomap *pru_arm_iomap)
+{
+ s16 status = SUART_SUCCESS;
+ OMAPL_McaspRegsOvly mcasp0Regs = (OMAPL_McaspRegsOvly)
+ pru_arm_iomap->mcasp_io_addr;
+ u32 *pu32SrCtlAddr = NULL;
+ if (u16srNum > 15) {
+ status = SUART_INVALID_SR_NUM;
+ } else {
+ pu32SrCtlAddr = (u32 *)&(mcasp0Regs->SRCTL0);
+ pu32SrCtlAddr += u16srNum;
+ *(pu32SrCtlAddr) = 0x000C;
+ }
+ return status;
+}
new file mode 100644
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: jitendra@mistralsolutions.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef _SUART_UTILS_H_
+#define _SUART_UTILS_H_
+
+#include<linux/types.h>
+
+/* ************ Serializers ***************** */
+#define PRU_SUART_SERIALIZER_0 (0u)
+#define PRU_SUART_SERIALIZER_1 (1u)
+#define PRU_SUART_SERIALIZER_2 (2u)
+#define PRU_SUART_SERIALIZER_3 (3u)
+#define PRU_SUART_SERIALIZER_4 (4u)
+#define PRU_SUART_SERIALIZER_5 (5u)
+#define PRU_SUART_SERIALIZER_6 (6u)
+#define PRU_SUART_SERIALIZER_7 (7u)
+#define PRU_SUART_SERIALIZER_8 (8u)
+#define PRU_SUART_SERIALIZER_9 (9u)
+#define PRU_SUART_SERIALIZER_10 (10u)
+#define PRU_SUART_SERIALIZER_11 (11u)
+#define PRU_SUART_SERIALIZER_12 (12u)
+#define PRU_SUART_SERIALIZER_13 (13u)
+#define PRU_SUART_SERIALIZER_14 (14u)
+#define PRU_SUART_SERIALIZER_15 (15u)
+#define PRU_SUART_SERIALIZER_NONE (16u)
+
+/* Total number of baud rates supported */
+#define SUART_NUM_OF_BAUDS_SUPPORTED 13
+
+#define MCASP_PDIR_VAL ( \
+ OMAPL_MCASP_PDIR_AFSR_OUTPUT<<OMAPL_MCASP_PDIR_AFSR_SHIFT | \
+ OMAPL_MCASP_PDIR_AHCLKR_OUTPUT<<OMAPL_MCASP_PDIR_AHCLKR_SHIFT | \
+ OMAPL_MCASP_PDIR_ACLKR_OUTPUT<<OMAPL_MCASP_PDIR_ACLKR_SHIFT | \
+ OMAPL_MCASP_PDIR_AFSX_OUTPUT<<OMAPL_MCASP_PDIR_AFSX_SHIFT | \
+ OMAPL_MCASP_PDIR_AHCLKX_OUTPUT<<OMAPL_MCASP_PDIR_AHCLKX_SHIFT | \
+ OMAPL_MCASP_PDIR_ACLKX_OUTPUT<<OMAPL_MCASP_PDIR_ACLKX_SHIFT)
+
+extern void suart_mcasp_config(u32 mcasp_addr, u32 txBaudValue,
+ u32 rxBaudValue, u32 oversampling,
+ arm_pru_iomap *pru_arm_iomap);
+
+extern short suart_asp_baud_set(u32 txBaudValue, u32 rxBaudValue,
+ u32 oversampling, arm_pru_iomap *pru_arm_iomap);
+
+extern short suart_asp_serializer_deactivate(u16 u16srNum,
+ arm_pru_iomap *pru_arm_iomap);
+
+extern void suart_mcasp_tx_serialzier_set(u32 serializerNum,
+ arm_pru_iomap *pru_arm_iomap);
+#endif
new file mode 100644
@@ -0,0 +1,1026 @@
+/*
+ * TI OMAPL PRU SUART Emulation device driver
+ * Author: subhasish@mistralsolutions.com
+ *
+ * This driver supports TI's PRU SUART Emulation and the
+ * specs for the same is available at <http://www.ti.com>
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed as is WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/module.h>
+#include <mach/da8xx.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/clk.h>
+#include <linux/serial_reg.h>
+#include <linux/delay.h>
+#include "omapl_suart_board.h"
+#include "suart_api.h"
+#include "suart_utils.h"
+#include "suart_err.h"
+
+#define NR_SUART 8
+#define DRV_NAME "davinci_pru_suart"
+#define DRV_DESC "TI PRU SUART Controller Driver v0.1"
+#define MAX_SUART_RETRIES 100
+#define SUART_CNTX_SZ 512
+#define PLATFORM_SUART_RES_SZ 3
+#define SUART_FIFO_TIMEOUT_DFLT 5
+#define SUART_FIFO_TIMEOUT_MIN 4
+#define SUART_FIFO_TIMEOUT_MAX 500
+
+#ifdef __SUART_DEBUG
+ #define __suart_debug(fmt, args...) \
+ printk(KERN_DEBUG "suart_debug: " fmt, ## args)
+#else
+ #define __suart_debug(fmt, args...)
+#endif
+
+#define __suart_err(fmt, args...) printk(KERN_ERR "suart_err: " fmt, ## args)
+
+/* Default timeout set to 5ms */
+static int suart_timeout = SUART_FIFO_TIMEOUT_DFLT;
+module_param(suart_timeout, int, S_IRUGO);
+MODULE_PARM_DESC(suart_timeout,
+ "fifo timeout in milli seconds (min: 4; max: 500)");
+
+struct suart_dma {
+ void *dma_vaddr_buff_tx;
+ void *dma_vaddr_buff_rx;
+ dma_addr_t dma_phys_addr_tx;
+ dma_addr_t dma_phys_addr_rx;
+};
+
+struct omapl_pru_suart {
+ struct uart_port port[NR_SUART];
+ arm_pru_iomap pru_arm_iomap;
+ struct semaphore port_sem[NR_SUART];
+ struct clk *clk_pru;
+ struct clk *clk_mcasp;
+ const struct firmware *fw;
+ suart_struct_handle suart_hdl[NR_SUART];
+ struct suart_dma suart_dma_addr[NR_SUART];
+ u32 clk_freq_pru;
+ u32 clk_freq_mcasp;
+ u32 tx_loadsz;
+};
+
+static u32 suart_get_duplex(struct omapl_pru_suart *soft_uart, u32 uart_no)
+{
+ return soft_uart->suart_hdl[uart_no].uartType;
+}
+
+static inline void __stop_tx(struct omapl_pru_suart *soft_uart, u32 uart_no)
+{
+ u16 txready;
+ u32 i;
+
+ /* Check if any TX in progress */
+ for (i = 0, txready = 1; (i < 10000) && txready; i++) {
+ txready = (pru_softuart_getTxStatus
+ (&soft_uart->suart_hdl[uart_no]) & CHN_TXRX_STATUS_RDY);
+ }
+ /* To stop tx, disable the TX interrupt */
+ suart_intr_clrmask(soft_uart->suart_hdl[uart_no].uartNum, PRU_TX_INTR,
+ CHN_TXRX_IE_MASK_CMPLT);
+ pru_softuart_clrTxStatus(&soft_uart->suart_hdl[uart_no]);
+}
+
+static void pru_suart_stop_tx(struct uart_port *port)
+{
+ struct omapl_pru_suart *soft_uart =
+ container_of(port, struct omapl_pru_suart, port[port->line]);
+ __stop_tx(soft_uart, port->line);
+}
+
+static void omapl_pru_tx_chars(struct omapl_pru_suart *soft_uart, u32 uart_no)
+{
+ struct circ_buf *xmit = &soft_uart->port[uart_no].state->xmit;
+ int count = 0;
+
+ if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_TX)) {
+ return;
+ }
+
+ if (down_trylock(&soft_uart->port_sem[uart_no]))
+ return;
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&soft_uart->port[uart_no])) {
+ pru_suart_stop_tx(&soft_uart->port[uart_no]);
+ up(&soft_uart->port_sem[uart_no]);
+ return;
+ }
+
+ for (count = 0; count <= soft_uart->tx_loadsz; count++) {
+ *((char *)soft_uart->suart_dma_addr[uart_no].dma_vaddr_buff_tx +
+ count) = xmit->buf[xmit->tail];
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ soft_uart->port[uart_no].icount.tx++;
+ if (uart_circ_empty(xmit)) {
+ uart_circ_clear(xmit);
+ break;
+ }
+ }
+
+ if (count == (SUART_FIFO_LEN + 1))
+ count = SUART_FIFO_LEN;
+
+ /* Write the character to the data port */
+ if (SUART_SUCCESS != pru_softuart_write(&soft_uart->suart_hdl[uart_no],
+ (unsigned int *)
+ &soft_uart->suart_dma_addr
+ [uart_no].dma_phys_addr_tx,
+ count)) {
+ __suart_err("failed to tx data\n");
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&soft_uart->port[uart_no]);
+
+#if 0
+ if (uart_circ_empty(xmit))
+ __stop_tx(soft_uart, uart_no);
+#endif
+}
+
+static void omapl_pru_rx_chars(struct omapl_pru_suart *soft_uart, u32 uart_no)
+{
+ struct tty_struct *tty = soft_uart->port[uart_no].state->port.tty;
+ char flags = TTY_NORMAL;
+ u16 rx_status, data_len = SUART_FIFO_LEN;
+ unsigned int data_len_read;
+ unsigned char suart_data[SUART_FIFO_LEN + 1];
+ int i = 0;
+
+ if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_RX))
+ return;
+ /* read the status */
+ rx_status = pru_softuart_getRxStatus(&soft_uart->suart_hdl[uart_no]);
+
+ /* check for errors */
+ if (rx_status & CHN_TXRX_STATUS_ERR) {
+ if (rx_status & CHN_TXRX_STATUS_FE)
+ soft_uart->port[uart_no].icount.frame++;
+ if (rx_status & CHN_TXRX_STATUS_OVRNERR)
+ soft_uart->port[uart_no].icount.overrun++;
+ if (rx_status & CHN_TXRX_STATUS_BI)
+ soft_uart->port[uart_no].icount.brk++;
+ rx_status &= soft_uart->port[uart_no].read_status_mask;
+ if (rx_status & CHN_TXRX_STATUS_FE)
+ flags = TTY_FRAME;
+ if (rx_status & CHN_TXRX_STATUS_OVRNERR)
+ flags = TTY_OVERRUN;
+ if (rx_status & CHN_TXRX_STATUS_BI)
+ flags = TTY_BREAK;
+
+#ifdef SUPPORT_SYSRQ
+ soft_uart->port[uart_no].sysrq = 0;
+#endif
+ } else {
+ pru_softuart_read_data(&soft_uart->suart_hdl[uart_no],
+ suart_data, data_len + 1,
+ &data_len_read);
+
+ for (i = 0; i <= data_len_read; i++) {
+ soft_uart->port[uart_no].icount.rx++;
+ /* check for sys rq */
+ if (uart_handle_sysrq_char
+ (&soft_uart->port[uart_no], suart_data))
+ continue;
+ }
+ /* update the tty data structure */
+ tty_insert_flip_string(tty, suart_data, data_len_read);
+ }
+
+ /* push data into tty */
+ pru_softuart_clrRxStatus(&soft_uart->suart_hdl[uart_no]);
+ spin_unlock(&soft_uart->port[uart_no].lock);
+ tty_flip_buffer_push(tty);
+ spin_lock(&soft_uart->port[uart_no].lock);
+}
+
+static irqreturn_t omapl_pru_suart_interrupt(int irq, void *dev_id)
+{
+ struct uart_port *port = dev_id;
+ struct omapl_pru_suart *soft_uart =
+ container_of(port, struct omapl_pru_suart, port[port->line]);
+ u16 txrx_flag;
+ u32 ret;
+ unsigned long flags = 0;
+ u16 uartNum = port->line + 1;
+
+ spin_lock_irqsave(&soft_uart->port[port->line].lock, flags);
+ do {
+ ret = pru_softuart_get_isrstatus(uartNum, &txrx_flag);
+ if (PRU_SUART_SUCCESS != ret) {
+ __suart_err("suart%d: failed to get interrupt, ret:"
+ " 0x%X txrx_flag 0x%X\n",
+ port->line, ret, txrx_flag);
+ spin_unlock_irqrestore(&soft_uart->
+ port[port->line].lock, flags);
+ return IRQ_NONE;
+ }
+ if ((PRU_RX_INTR & txrx_flag) == PRU_RX_INTR) {
+ pru_intr_clr_isrstatus(uartNum, PRU_RX_INTR);
+ if ((soft_uart->port[port->line].ignore_status_mask &
+ CHN_TXRX_STATUS_RDY) == CHN_TXRX_STATUS_RDY) {
+ pru_softuart_clrRxStatus(&soft_uart->suart_hdl
+ [port->line]);
+ } else {
+ omapl_pru_rx_chars(soft_uart, port->line);
+ }
+ }
+
+ if ((PRU_TX_INTR & txrx_flag) == PRU_TX_INTR) {
+ pru_intr_clr_isrstatus(uartNum, PRU_TX_INTR);
+ pru_softuart_clrTxStatus(&soft_uart->suart_hdl
+ [port->line]);
+ up(&soft_uart->port_sem[port->line]);
+ omapl_pru_tx_chars(soft_uart, port->line);
+ }
+ } while (txrx_flag & (PRU_RX_INTR | PRU_TX_INTR));
+
+ spin_unlock_irqrestore(&soft_uart->port[port->line].lock, flags);
+ return IRQ_HANDLED;
+}
+
+static void pru_suart_stop_rx(struct uart_port *port)
+{
+ struct omapl_pru_suart *soft_uart =
+ container_of(port, struct omapl_pru_suart, port[port->line]);
+ /* disable rx interrupt */
+ suart_intr_clrmask(soft_uart->suart_hdl[port->line].uartNum,
+ PRU_RX_INTR, CHN_TXRX_IE_MASK_BI
+ | CHN_TXRX_IE_MASK_FE | CHN_TXRX_IE_MASK_CMPLT
+ | CHN_TXRX_IE_MASK_TIMEOUT);
+}
+
+static void pru_suart_enable_ms(struct uart_port *port)
+{
+ __suart_err("modem control timer not supported\n");
+}
+
+static void pru_suart_start_tx(struct uart_port *port)
+{
+ struct omapl_pru_suart *soft_uart =
+ container_of(port, struct omapl_pru_suart, port[port->line]);
+ /* unmask the tx interrupts */
+
+ suart_intr_setmask(soft_uart->suart_hdl[port->line].uartNum,
+ PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);
+ omapl_pru_tx_chars(soft_uart, port->line);
+}
+
+static unsigned int pru_suart_tx_empty(struct uart_port *port)
+{
+ struct omapl_pru_suart *soft_uart =
+ container_of(port, struct omapl_pru_suart, port[port->line]);
+
+ return (pru_softuart_getTxStatus(&soft_uart->suart_hdl[port->line])
+ & CHN_TXRX_STATUS_RDY) ? 0 : TIOCSER_TEMT;
+}
+
+static unsigned int pru_suart_get_mctrl(struct uart_port *port)
+{
+ return -ENOTSUPP;
+}
+
+static void pru_suart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ __suart_debug("modem control not supported\n");
+}
+
+static void pru_suart_break_ctl(struct uart_port *port, int break_state)
+{
+ struct omapl_pru_suart *soft_uart =
+ container_of(port, struct omapl_pru_suart, port[port->line]);
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ if (break_state == -1)
+ suart_intr_clrmask(soft_uart->suart_hdl[port->line].uartNum,
+ PRU_RX_INTR, CHN_TXRX_IE_MASK_BI);
+ else
+ suart_intr_setmask(soft_uart->suart_hdl[port->line].uartNum,
+ PRU_RX_INTR, CHN_TXRX_IE_MASK_BI);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void pru_suart_set_termios(struct uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
+{
+ struct omapl_pru_suart *soft_uart =
+ container_of(port, struct omapl_pru_suart, port[port->line]);
+ unsigned char cval = 0;
+ unsigned long flags = 0;
+ unsigned int baud = 0;
+ unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
+
+/*
+ * Do not allow unsupported configurations to be set
+ */
+ if (1) {
+ termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR | CSTOPB
+ | PARENB | PARODD | CMSPAR);
+ termios->c_cflag |= CLOCAL;
+ }
+
+ switch (termios->c_cflag & CSIZE) {
+ case CS6:
+ cval = ePRU_SUART_DATA_BITS6;
+ break;
+ case CS7:
+ cval = ePRU_SUART_DATA_BITS7;
+ break;
+ default:
+ case CS8:
+ cval = ePRU_SUART_DATA_BITS8;
+ break;
+ }
+ /*
+ * We do not support CS5.
+ */
+ if ((termios->c_cflag & CSIZE) == CS5) {
+ termios->c_cflag &= ~CSIZE;
+ termios->c_cflag |= old_csize;
+ }
+ if (SUART_SUCCESS != pru_softuart_setdatabits
+ (&soft_uart->suart_hdl[port->line], cval, cval))
+ __suart_err("failed to set data bits to: %d\n", cval);
+
+/*
+ * Ask the core to calculate the divisor for us.
+ */
+ baud = uart_get_baud_rate(port, termios, old,
+ port->uartclk / 16 / 0xffff,
+ port->uartclk / 16);
+
+/*
+ * Ok, we're now changing the port state. Do it with
+ * interrupts disabled.
+ */
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* Set the baud */
+ if (SUART_SUCCESS !=
+ pru_softuart_setbaud(&soft_uart->suart_hdl[port->line],
+ SUART_DEFAULT_BAUD / baud,
+ SUART_DEFAULT_BAUD / baud))
+ __suart_err("failed to set baud to: %d\n", baud);
+
+/*
+ * update port->read_config_mask and port->ignore_config_mask
+ * to indicate the events we are interested in receiving
+ */
+ suart_intr_setmask(soft_uart->suart_hdl[port->line].uartNum,
+ PRU_RX_INTR, SUART_GBL_INTR_ERR_MASK);
+ port->read_status_mask = 0;
+ if (termios->c_iflag & INPCK) { /* Input parity check not supported,
+ just enabled FE */
+ port->read_status_mask |= CHN_TXRX_STATUS_FE;
+ suart_intr_setmask(soft_uart->suart_hdl[port->line].uartNum,
+ PRU_RX_INTR, CHN_TXRX_IE_MASK_FE);
+ }
+ if (termios->c_iflag & (BRKINT | PARMRK)) {
+ port->read_status_mask |= CHN_TXRX_STATUS_BI;
+ suart_intr_setmask(soft_uart->suart_hdl[port->line].uartNum,
+ PRU_RX_INTR, CHN_TXRX_IE_MASK_BI);
+ }
+/*
+ * Characteres to ignore
+ */
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNBRK) {
+ port->ignore_status_mask |= CHN_TXRX_STATUS_BI;
+ /*
+ * If we're ignoring break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (termios->c_iflag & IGNPAR) {
+ port->ignore_status_mask |=
+ (CHN_TXRX_STATUS_OVRNERR | CHN_TXRX_STATUS_FE);
+ /*
+ * Overrun in case of RX
+ * Underrun in case of TX
+ */
+ suart_intr_clrmask(soft_uart->
+ suart_hdl[port->line].uartNum,
+ PRU_RX_INTR, CHN_TXRX_IE_MASK_FE);
+ }
+ suart_intr_clrmask(soft_uart->suart_hdl[port->line].uartNum,
+ PRU_RX_INTR, CHN_TXRX_IE_MASK_BI);
+ }
+/*
+ * ignore all characters if CREAD is not set
+ */
+ if ((termios->c_cflag & CREAD) == 0) {
+ port->ignore_status_mask |= CHN_TXRX_STATUS_RDY;
+ pru_suart_stop_rx(port);
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+ /* Don't rewrite B0 */
+ if (tty_termios_baud_rate(termios))
+ tty_termios_encode_baud_rate(termios, baud, baud);
+}
+
+/*
+ * Grab any interrupt resources and initialise any low level driver
+ * state. Enable the port for reception. It should not activate
+ * RTS nor DTR; this will be done via a separate call to set_mctrl.
+ *
+ * This method will only be called when the port is initially opened.
+ *
+ * Locking: port_sem taken.
+ * Interrupts: globally disabled.
+ */
+static int pru_suart_startup(struct uart_port *port)
+{
+ struct omapl_pru_suart *soft_uart =
+ container_of(port, struct omapl_pru_suart, port[port->line]);
+ int retval;
+
+ /*
+ * Disable interrupts from this port
+ */
+ suart_intr_clrmask(soft_uart->suart_hdl[port->line].uartNum,
+ PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);
+ suart_intr_clrmask(soft_uart->suart_hdl[port->line].uartNum,
+ PRU_RX_INTR, CHN_TXRX_IE_MASK_BI
+ | CHN_TXRX_IE_MASK_FE | CHN_TXRX_IE_MASK_CMPLT
+ | CHN_TXRX_IE_MASK_TIMEOUT);
+
+ retval = request_irq(port->irq, omapl_pru_suart_interrupt,
+ port->irqflags, "suart_irq", port);
+ if (retval) {
+ free_irq(port->irq, port); /* should we free this if err */
+ goto out;
+ }
+ /*
+ * enable interrupts from this port
+ */
+ suart_intr_setmask(soft_uart->suart_hdl[port->line].uartNum,
+ PRU_RX_INTR, SUART_GBL_INTR_ERR_MASK);
+
+ suart_intr_setmask(soft_uart->suart_hdl[port->line].uartNum,
+ PRU_RX_INTR, CHN_TXRX_IE_MASK_BI
+ | CHN_TXRX_IE_MASK_FE | CHN_TXRX_IE_MASK_CMPLT
+ | CHN_TXRX_IE_MASK_TIMEOUT);
+
+ suart_intr_setmask(soft_uart->suart_hdl[port->line].uartNum,
+ PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);
+
+ if ((suart_get_duplex(soft_uart, port->line) & ePRU_SUART_HALF_TX)
+ == ePRU_SUART_HALF_TX) {
+ suart_pru_to_host_intr_enable(soft_uart->
+ suart_hdl[port->line].uartNum,
+ PRU_TX_INTR, true);
+ }
+ /* Seed RX if port is half-rx or full-duplex */
+ if ((suart_get_duplex(soft_uart, port->line) & ePRU_SUART_HALF_RX)
+ == ePRU_SUART_HALF_RX) {
+ suart_pru_to_host_intr_enable(soft_uart->
+ suart_hdl[port->line].uartNum,
+ PRU_RX_INTR, true);
+ pru_softuart_read(&soft_uart->suart_hdl[port->line],
+ (unsigned int *)
+ &soft_uart->suart_dma_addr[port->line].
+ dma_phys_addr_rx, SUART_FIFO_LEN);
+ }
+
+out:
+ return retval;
+}
+
+/*
+ * Disable the port, disable any break condition that may be in
+ * effect, and free any interrupt resources. It should not disable
+ * RTS nor DTR; this will have already been done via a separate
+ * call to set_mctrl.
+ *
+ * Drivers must not access port->info once this call has completed.
+ *
+ * This method will only be called when there are no more users of
+ * this port.
+ *
+ * Locking: port_sem taken.
+ * Interrupts: caller dependent.
+ */
+
+static void pru_suart_shutdown(struct uart_port *port)
+{
+ struct omapl_pru_suart *soft_uart =
+ container_of(port, struct omapl_pru_suart, port[port->line]);
+
+ /*
+ * Disable interrupts from this port
+ */
+ /* Disable BI and FE intr */
+ suart_intr_clrmask(soft_uart->suart_hdl[port->line].uartNum,
+ PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);
+ suart_intr_clrmask(soft_uart->suart_hdl[port->line].uartNum,
+ PRU_RX_INTR, CHN_TXRX_IE_MASK_BI
+ | CHN_TXRX_IE_MASK_FE | CHN_TXRX_IE_MASK_CMPLT
+ | CHN_TXRX_IE_MASK_TIMEOUT);
+
+ /* free interrupts */
+ free_irq(port->irq, port);
+}
+
+/*
+ * Return a pointer to a string constant describing the specified
+ * port, or return NULL, in which case the string 'unknown' is
+ * substituted.
+ *
+ * Locking: none.
+ * Interrupts: caller dependent.
+ */
+
+static const char *pru_suart_type(struct uart_port *port)
+{
+ return "suart_tty";
+}
+
+/*
+ * Release any memory and IO region resources currently in use by
+ * the port.
+ *
+ * Locking: none.
+ * Interrupts: caller dependent.
+ */
+
+static void pru_suart_release_port(struct uart_port *port)
+{
+ struct omapl_pru_suart *soft_uart =
+ container_of(port, struct omapl_pru_suart, port[port->line]);
+ struct platform_device *pdev = to_platform_device(port->dev);
+
+ if (0 != pru_softuart_close(&soft_uart->suart_hdl[port->line])) {
+ dev_err(&pdev->dev, "failed to close suart\n");
+ }
+ return;
+}
+
+/*
+ * Request any memory and IO region resources required by the port.
+ * If any fail, no resources should be registered when this function
+ * returns, and it should return -EBUSY on failure.
+ *
+ * Locking: none.
+ * Interrupts: caller dependent.
+ *
+ * We need to d/l the f/w in probe and since this api
+ * is called per uart, the request_mem_region should
+ * be called in probe itself.
+ * We call the pru_open routein only here. not sure if aesthetically correct.
+ */
+static int pru_suart_request_port(struct uart_port *port)
+{
+ struct omapl_pru_suart *soft_uart =
+ container_of(port, struct omapl_pru_suart, port[port->line]);
+ struct platform_device *pdev = to_platform_device(port->dev);
+ suart_config pru_suart_config;
+ u32 timeout = 0;
+ u32 err = 0;
+ if (soft_uart == NULL) {
+ __suart_err("soft_uart ptr failed\n");
+ return -ENODEV;
+ }
+ err = pru_softuart_open(&soft_uart->suart_hdl[port->line]);
+ if (PRU_SUART_SUCCESS != err) {
+ dev_err(&pdev->dev, "failed to open suart: %d\n", err);
+ err = -ENODEV;
+ goto exit;
+ }
+
+ /* set fifo timeout */
+ if (SUART_FIFO_TIMEOUT_MIN > suart_timeout) {
+ __suart_err("fifo timeout less than %d ms not supported\n",
+ SUART_FIFO_TIMEOUT_MIN);
+ suart_timeout = SUART_FIFO_TIMEOUT_MIN;
+ } else if (SUART_FIFO_TIMEOUT_MAX < suart_timeout) {
+ __suart_err("fifo timeout more than %d ms not supported\n",
+ SUART_FIFO_TIMEOUT_MAX);
+ suart_timeout = SUART_FIFO_TIMEOUT_MAX;
+ }
+
+ /* This is only for x8 */
+ timeout = (SUART_DEFAULT_BAUD * suart_timeout) / 1000;
+ pru_set_fifo_timeout(timeout);
+
+ if (soft_uart->suart_hdl[port->line].uartNum == PRU_SUART_UART1) {
+ pru_suart_config.TXSerializer = PRU_SUART1_CONFIG_TX_SER;
+ pru_suart_config.RXSerializer = PRU_SUART1_CONFIG_RX_SER;
+ } else if (soft_uart->suart_hdl[port->line].uartNum ==
+ PRU_SUART_UART2) {
+ pru_suart_config.TXSerializer = PRU_SUART2_CONFIG_TX_SER;
+ pru_suart_config.RXSerializer = PRU_SUART2_CONFIG_RX_SER;
+ } else if (soft_uart->suart_hdl[port->line].uartNum ==
+ PRU_SUART_UART3) {
+ pru_suart_config.TXSerializer = PRU_SUART3_CONFIG_TX_SER;
+ pru_suart_config.RXSerializer = PRU_SUART3_CONFIG_RX_SER;
+ } else if (soft_uart->suart_hdl[port->line].uartNum ==
+ PRU_SUART_UART4) {
+ pru_suart_config.TXSerializer = PRU_SUART4_CONFIG_TX_SER;
+ pru_suart_config.RXSerializer = PRU_SUART4_CONFIG_RX_SER;
+ } else if (soft_uart->suart_hdl[port->line].uartNum ==
+ PRU_SUART_UART5) {
+ pru_suart_config.TXSerializer = PRU_SUART5_CONFIG_TX_SER;
+ pru_suart_config.RXSerializer = PRU_SUART5_CONFIG_RX_SER;
+ } else if (soft_uart->suart_hdl[port->line].uartNum ==
+ PRU_SUART_UART6) {
+ pru_suart_config.TXSerializer = PRU_SUART6_CONFIG_TX_SER;
+ pru_suart_config.RXSerializer = PRU_SUART6_CONFIG_RX_SER;
+ } else if (soft_uart->suart_hdl[port->line].uartNum ==
+ PRU_SUART_UART7) {
+ pru_suart_config.TXSerializer = PRU_SUART7_CONFIG_TX_SER;
+ pru_suart_config.RXSerializer = PRU_SUART7_CONFIG_RX_SER;
+ } else if (soft_uart->suart_hdl[port->line].uartNum ==
+ PRU_SUART_UART8) {
+ pru_suart_config.TXSerializer = PRU_SUART8_CONFIG_TX_SER;
+ pru_suart_config.RXSerializer = PRU_SUART8_CONFIG_RX_SER;
+ } else {
+ return -ENOTSUPP;
+ }
+
+ /* Some defaults to startup. reconfigured by terimos later */
+ pru_suart_config.txClkDivisor = 1;
+ pru_suart_config.rxClkDivisor = 1;
+ pru_suart_config.txBitsPerChar = ePRU_SUART_DATA_BITS8;
+ pru_suart_config.rxBitsPerChar = ePRU_SUART_DATA_BITS8;
+ pru_suart_config.Oversampling = SUART_DEFAULT_OVRSMPL;
+
+ if (PRU_SUART_SUCCESS !=
+ pru_softuart_setconfig(&soft_uart->suart_hdl[port->line],
+ &pru_suart_config)) {
+ dev_err(&pdev->dev,
+ "pru_softuart_setconfig: failed to set config: %X\n",
+ err);
+ }
+exit:
+ return err;
+}
+
+/*
+ * Perform any autoconfiguration steps required for the port. `flag`
+ * contains a bit mask of the required configuration. UART_CONFIG_TYPE
+ * indicates that the port requires detection and identification.
+ * port->type should be set to the type found, or PORT_UNKNOWN if
+ * no port was detected.
+ *
+ * UART_CONFIG_IRQ indicates autoconfiguration of the interrupt signal,
+ * which should be probed using standard kernel autoprobing techniques.
+ * This is not necessary on platforms where ports have interrupts
+ * internally hard wired (eg, system on a chip implementations).
+ *
+ * Locking: none.
+ * Interrupts: caller dependent.
+ */
+
+static void pru_suart_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE && pru_suart_request_port(port) == 0)
+ port->type = PORT_OMAPL_PRU_SUART;
+}
+
+/*
+ * Verify the new serial port information contained within serinfo is
+ * suitable for this port type.
+ *
+ * Locking: none.
+ * Interrupts: caller dependent.
+ */
+static int pru_suart_verify_port(struct uart_port *port,
+ struct serial_struct *ser)
+{
+ struct omapl_pru_suart *soft_uart =
+ container_of(port, struct omapl_pru_suart, port[port->line]);
+ int ret = 0;
+
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_OMAPL_PRU_SUART)
+ ret = -EINVAL;
+ if (soft_uart->port[port->line].irq != ser->irq)
+ ret = -EINVAL;
+ if (ser->io_type != UPIO_MEM)
+ ret = -EINVAL;
+ if (soft_uart->port[port->line].uartclk / 16 != ser->baud_base)
+ ret = -EINVAL;
+ if ((void *)soft_uart->port[port->line].mapbase != ser->iomem_base)
+ ret = -EINVAL;
+ if (soft_uart->port[port->line].iobase != ser->port)
+ ret = -EINVAL;
+ return ret;
+}
+
+static struct uart_ops pru_suart_ops = {
+ .tx_empty = pru_suart_tx_empty,
+ .set_mctrl = pru_suart_set_mctrl,
+ .get_mctrl = pru_suart_get_mctrl,
+ .stop_tx = pru_suart_stop_tx,
+ .start_tx = pru_suart_start_tx,
+ .stop_rx = pru_suart_stop_rx,
+ .enable_ms = pru_suart_enable_ms,
+ .break_ctl = pru_suart_break_ctl,
+ .startup = pru_suart_startup,
+ .shutdown = pru_suart_shutdown,
+ .set_termios = pru_suart_set_termios,
+ .type = pru_suart_type,
+ .release_port = pru_suart_release_port,
+ .request_port = pru_suart_request_port,
+ .config_port = pru_suart_config_port,
+ .verify_port = pru_suart_verify_port,
+};
+
+static struct uart_driver pru_suart_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = DRV_NAME,
+ .dev_name = "ttySU",
+ .major = 0,
+ .minor = 16,
+ .nr = NR_SUART,
+};
+
+static int __devinit omapl_pru_suart_probe(struct platform_device *pdev)
+{
+ struct omapl_pru_suart *soft_uart;
+ struct resource *res_mem[PLATFORM_SUART_RES_SZ];
+ int err, i;
+ unsigned char *fw_data = NULL;
+
+ soft_uart = kzalloc(sizeof(struct omapl_pru_suart), GFP_KERNEL);
+ if (!soft_uart)
+ return -ENOMEM;
+
+ for (i = 0; i < PLATFORM_SUART_RES_SZ; i++) {
+ res_mem[i] = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ if (!res_mem[i]) {
+ dev_err(&pdev->dev,
+ "unable to get pru memory resources!\n");
+ err = -ENODEV;
+ goto probe_exit;
+ }
+ }
+
+ if (!request_mem_region(res_mem[0]->start, resource_size(res_mem[0]),
+ dev_name(&pdev->dev))) {
+ dev_err(&pdev->dev, "pru memory region already claimed!\n");
+ err = -EBUSY;
+ goto probe_exit;
+ }
+ if (!request_mem_region(res_mem[1]->start, resource_size(res_mem[1]),
+ dev_name(&pdev->dev))) {
+ dev_err(&pdev->dev, "mcasp memory region already claimed!\n");
+ err = -EBUSY;
+ goto probe_exit_1;
+ }
+
+ soft_uart->pru_arm_iomap.pru_io_addr = ioremap(res_mem[0]->start,
+ resource_size(res_mem[0]));
+ if (!soft_uart->pru_arm_iomap.pru_io_addr) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ err = -ENOMEM;
+ goto probe_exit_free_region;
+ }
+ soft_uart->pru_arm_iomap.mcasp_io_addr = ioremap(res_mem[1]->start,
+ resource_size(res_mem[1]));
+ if (!soft_uart->pru_arm_iomap.mcasp_io_addr) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ err = -ENOMEM;
+ goto probe_exit_iounmap_1;
+ }
+
+ soft_uart->clk_pru = clk_get(&pdev->dev, "pruss");
+ if (IS_ERR(soft_uart->clk_pru)) {
+ dev_err(&pdev->dev, "no clock available: pruss\n");
+ err = -ENODEV;
+ soft_uart->clk_pru = NULL;
+ goto probe_exit_iounmap_2;
+ }
+ soft_uart->clk_freq_pru = clk_get_rate(soft_uart->clk_pru);
+
+ /* mcasp_clk is tied with mcasp driver, hence using mcasp_pru */
+ soft_uart->clk_mcasp = clk_get(NULL, "mcasp_pru");
+ if (IS_ERR(soft_uart->clk_mcasp)) {
+ dev_err(&pdev->dev, "no clock available: mcasp\n");
+ err = -ENODEV;
+ soft_uart->clk_mcasp = NULL;
+ goto probe_exit_clk_pru;
+ }
+ soft_uart->clk_freq_mcasp = clk_get_rate(soft_uart->clk_mcasp);
+ clk_enable(soft_uart->clk_mcasp);
+ clk_enable(soft_uart->clk_pru);
+ err = request_firmware(&soft_uart->fw, "PRU_SUART_Emulation.bin",
+ &pdev->dev);
+ if (err) {
+ dev_err(&pdev->dev, "can't load firmware\n");
+ err = -ENODEV;
+ goto probe_exit_clk;
+ }
+ dev_info(&pdev->dev, "fw size %td. downloading...\n",
+ soft_uart->fw->size);
+
+ /* download firmware into pru & init */
+ fw_data = kmalloc(soft_uart->fw->size, GFP_KERNEL);
+ memcpy((void *)fw_data, (const void *)soft_uart->fw->data,
+ soft_uart->fw->size);
+
+ soft_uart->pru_arm_iomap.pFifoBufferPhysBase = (void *)res_mem[2]->start;
+ soft_uart->pru_arm_iomap.pFifoBufferVirtBase =
+ (void *)ioremap(res_mem[2]->start, resource_size(res_mem[2]));
+ if (!soft_uart->pru_arm_iomap.pFifoBufferVirtBase) {
+ __suart_err("Failed to allocate shared ram.\n");
+ err = -EFAULT;
+ goto probe_release_fw;
+ }
+
+ soft_uart->pru_arm_iomap.pru_clk_freq =
+ (soft_uart->clk_freq_pru / 1000000);
+
+ err = pru_softuart_init(SUART_DEFAULT_BAUD, SUART_DEFAULT_BAUD,
+ SUART_DEFAULT_OVRSMPL, fw_data,
+ soft_uart->fw->size, &soft_uart->pru_arm_iomap);
+ if (err) {
+ dev_err(&pdev->dev, "pru init error\n");
+ err = -ENODEV;
+ kfree((const void *)fw_data);
+ goto probe_exit_iounmap_3;
+ }
+ kfree((const void *)fw_data);
+
+ for (i = 0; i < NR_SUART; i++) {
+ soft_uart->port[i].ops = &pru_suart_ops;
+ soft_uart->port[i].iotype = UPIO_MEM; /* user conf parallel io */
+ soft_uart->port[i].flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
+ soft_uart->port[i].mapbase = res_mem[1]->start;
+ soft_uart->port[i].membase =
+ (unsigned char *)&soft_uart->pru_arm_iomap;
+ soft_uart->port[i].type = PORT_OMAPL_PRU_SUART;
+ soft_uart->port[i].irq = platform_get_irq(pdev, i);
+ soft_uart->port[i].dev = &pdev->dev;
+ soft_uart->port[i].irqflags = IRQF_SHARED;
+ soft_uart->port[i].uartclk = soft_uart->clk_freq_mcasp; /* 24MHz */
+ soft_uart->port[i].fifosize = SUART_FIFO_LEN;
+ soft_uart->tx_loadsz = SUART_FIFO_LEN;
+ soft_uart->port[i].custom_divisor = 1;
+ soft_uart->port[i].line = i; /* need the id/line from pdev */
+ soft_uart->suart_hdl[i].uartNum = i + 1;
+ spin_lock_init(&soft_uart->port[i].lock);
+ soft_uart->port[i].serial_in = NULL;
+
+ soft_uart->suart_dma_addr[i].dma_vaddr_buff_tx =
+ soft_uart->pru_arm_iomap.pFifoBufferVirtBase +
+ (2 * SUART_CNTX_SZ * i);
+
+ soft_uart->suart_dma_addr[i].dma_vaddr_buff_rx =
+ soft_uart->pru_arm_iomap.pFifoBufferVirtBase +
+ ((2 * SUART_CNTX_SZ * i) + SUART_CNTX_SZ);
+
+ soft_uart->suart_dma_addr[i].dma_phys_addr_tx =
+ (dma_addr_t)soft_uart->pru_arm_iomap.pFifoBufferPhysBase +
+ (2 * SUART_CNTX_SZ * i);
+
+ soft_uart->suart_dma_addr[i].dma_phys_addr_rx =
+ (dma_addr_t)soft_uart->pru_arm_iomap.pFifoBufferPhysBase +
+ ((2 * SUART_CNTX_SZ * i) + SUART_CNTX_SZ);
+
+ soft_uart->port[i].serial_out = NULL;
+ uart_add_one_port(&pru_suart_reg, &soft_uart->port[i]);
+ sema_init(&soft_uart->port_sem[i], 1);
+ }
+ platform_set_drvdata(pdev, &soft_uart->port[0]);
+
+ dev_info(&pdev->dev,
+ "%s device registered"
+ "(pru_clk=%d, asp_clk=%d)\n",
+ DRV_NAME, soft_uart->clk_freq_pru, soft_uart->clk_freq_mcasp);
+
+ return 0;
+
+probe_exit_iounmap_3:
+ iounmap(soft_uart->pru_arm_iomap.pFifoBufferVirtBase);
+probe_release_fw:
+ release_firmware(soft_uart->fw);
+probe_exit_clk:
+ clk_put(soft_uart->clk_mcasp);
+probe_exit_clk_pru:
+ clk_put(soft_uart->clk_pru);
+probe_exit_iounmap_2:
+ iounmap(soft_uart->pru_arm_iomap.mcasp_io_addr);
+probe_exit_iounmap_1:
+ iounmap(soft_uart->pru_arm_iomap.pru_io_addr);
+probe_exit_free_region:
+ release_mem_region(res_mem[1]->start, resource_size(res_mem[1]));
+probe_exit_1:
+ release_mem_region(res_mem[0]->start, resource_size(res_mem[0]));
+probe_exit:
+ kfree(soft_uart);
+ return err;
+}
+
+static int __devexit omapl_pru_suart_remove(struct platform_device *pdev)
+{
+ struct omapl_pru_suart *soft_uart = platform_get_drvdata(pdev);
+ struct resource *res_mem[PLATFORM_SUART_RES_SZ];
+ int i;
+ u32 err = 0;
+
+ platform_set_drvdata(pdev, NULL);
+
+ for (i = 0; i < PLATFORM_SUART_RES_SZ; i++) {
+ res_mem[i] = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ if (!res_mem[i]) {
+ dev_err(&pdev->dev,
+ "unable to get pru memory resources!\n");
+ err = -ENODEV;
+ }
+ }
+
+ if (soft_uart) {
+ for (i = 0; i < NR_SUART; i++) {
+ uart_remove_one_port(&pru_suart_reg,
+ &soft_uart->port[i]);
+ }
+ }
+ release_firmware(soft_uart->fw);
+ clk_put(soft_uart->clk_mcasp);
+ clk_put(soft_uart->clk_pru);
+ clk_disable(soft_uart->clk_mcasp);
+ clk_disable(soft_uart->clk_pru);
+ iounmap(soft_uart->pru_arm_iomap.mcasp_io_addr);
+ iounmap(soft_uart->pru_arm_iomap.pru_io_addr);
+ iounmap(soft_uart->pru_arm_iomap.pFifoBufferVirtBase);
+ release_mem_region(res_mem[0]->start, resource_size(res_mem[0]));
+ release_mem_region(res_mem[1]->start, resource_size(res_mem[1]));
+ kfree(soft_uart);
+ return err;
+}
+
+#define omapl_pru_suart_suspend NULL
+#define omapl_pru__suart_resume NULL
+
+static struct platform_driver serial_omapl_pru_driver = {
+ .probe = omapl_pru_suart_probe,
+ .remove = __devexit_p(omapl_pru_suart_remove),
+ .suspend = omapl_pru_suart_suspend,
+ .resume = omapl_pru__suart_resume,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pru_suart_init(void)
+{
+ int ret;
+
+ pru_suart_reg.nr = NR_SUART;
+ ret = uart_register_driver(&pru_suart_reg);
+ if (ret)
+ return ret;
+ ret = platform_driver_register(&serial_omapl_pru_driver);
+ if (ret)
+ goto out;
+
+ __suart_debug("SUART serial driver loaded\n");
+ return ret;
+out:
+ uart_unregister_driver(&pru_suart_reg);
+ return ret;
+}
+
+module_init(pru_suart_init);
+
+static void __exit omapl_pru_suart_exit(void)
+{
+ platform_driver_unregister(&serial_omapl_pru_driver);
+ uart_unregister_driver(&pru_suart_reg);
+ __suart_debug("SUART serial driver unloaded\n");
+}
+
+module_exit(omapl_pru_suart_exit);
+
+/* Module information */
+MODULE_AUTHOR("Subhasish Ghosh <subhasish@mistralsolutions.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRV_DESC);