From patchwork Fri Dec 31 12:18:14 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Subhasish Ghosh X-Patchwork-Id: 442261 Received: from comal.ext.ti.com (comal.ext.ti.com [198.47.26.152]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id oBVC8or0004636 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 31 Dec 2010 12:09:13 GMT Received: from dlep34.itg.ti.com ([157.170.170.115]) by comal.ext.ti.com (8.13.7/8.13.7) with ESMTP id oBVC6ZHh030684 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Fri, 31 Dec 2010 06:06:35 -0600 Received: from linux.omap.com (localhost [127.0.0.1]) by dlep34.itg.ti.com (8.13.7/8.13.7) with ESMTP id oBVC6Z4I001915; Fri, 31 Dec 2010 06:06:35 -0600 (CST) Received: from linux.omap.com (localhost [127.0.0.1]) by linux.omap.com (Postfix) with ESMTP id DCCB38062A; Fri, 31 Dec 2010 06:06:34 -0600 (CST) X-Original-To: davinci-linux-open-source@linux.davincidsp.com Delivered-To: davinci-linux-open-source@linux.davincidsp.com Received: from dflp53.itg.ti.com (dflp53.itg.ti.com [128.247.5.6]) by linux.omap.com (Postfix) with ESMTP id 84F368062A for ; Fri, 31 Dec 2010 06:06:32 -0600 (CST) Received: from medina.ext.ti.com (localhost [127.0.0.1]) by dflp53.itg.ti.com (8.13.8/8.13.8) with ESMTP id oBVC6WoA016261 for ; Fri, 31 Dec 2010 06:06:32 -0600 (CST) Received: from psmtp.com (na3sys009amx228.postini.com [74.125.149.112]) by medina.ext.ti.com (8.13.7/8.13.7) with SMTP id oBVC6VXG004097 for ; Fri, 31 Dec 2010 06:06:31 -0600 Received: from source ([209.85.160.45]) by na3sys009amx228.postini.com ([74.125.148.10]) with SMTP; Fri, 31 Dec 2010 07:06:31 EST Received: by mail-pw0-f45.google.com with SMTP id 6so1979835pwj.4 for ; Fri, 31 Dec 2010 04:06:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:from:to:cc:subject:date :message-id:x-mailer:in-reply-to:references; bh=5/V5dsDIf0U0x3e8w4apDR1MOLKLQc2/gq7jbOOs7oQ=; b=aIG2ajX25Cs01ursBuM9cg1tAV1lqRRoAHFcENKrrd+f3J8rE+yxjK9wZs7sJ8WDuI s4ZA2bjYhfSAvGPE6UPu4oE28JgbdFTVzGTEFqxKr5sYRhHL9VivHnh+o2Ukfgzk28S+ 9oYDanBGPVab/w5rY5u5VZHvox0lbtek5phdg= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; b=cBq4KIKwtKhs1TpOCvgb0g55sQuGJU6mLru7EQ6o3Y/wGD0cjbxlZD8aCj69RccdwB u8X2767IKx0/tCFjtAQfN9wbJG4lm5xS+3FiLnm+vNQ3nDkUBA1oJrLWBsTsxneQQ7QZ z51/reILef3E2mHR4tEGwVFSc5EroBjo6B8jM= Received: by 10.142.127.19 with SMTP id z19mr14057061wfc.82.1293797190632; Fri, 31 Dec 2010 04:06:30 -0800 (PST) Received: from localhost ([59.97.0.30]) by mx.google.com with ESMTPS id v19sm23967931wfh.0.2010.12.31.04.06.15 (version=TLSv1/SSLv3 cipher=RC4-MD5); Fri, 31 Dec 2010 04:06:29 -0800 (PST) From: Subhasish Ghosh To: davinci-linux-open-source@linux.davincidsp.com Subject: [RFC: PATCH 5/5] da850: tty compliant driver for TI's PRU SoftUART Emulation. Date: Fri, 31 Dec 2010 17:48:14 +0530 Message-Id: <1293797894-15964-5-git-send-email-subhasish@mistralsolutions.com> X-Mailer: git-send-email 1.7.2.3 In-Reply-To: <1293797894-15964-1-git-send-email-subhasish@mistralsolutions.com> References: <1293797894-15964-1-git-send-email-subhasish@mistralsolutions.com> X-pstn-neptune: 0/0/0.00/0 X-pstn-levels: (S:61.31998/99.90000 CV:99.9000 FC:95.5390 LC:95.5390 R:95.9108 P:95.9108 M:97.0282 C:98.6951 ) X-pstn-settings: 2 (0.5000:0.0750) s cv GT3 gt2 gt1 r p m c X-pstn-addresses: from [db-null] Cc: m-watkins@ti.com, sshtylyov@mvista.com, Subhasish Ghosh X-BeenThere: davinci-linux-open-source@linux.davincidsp.com X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: davinci-linux-open-source-bounces@linux.davincidsp.com Errors-To: davinci-linux-open-source-bounces@linux.davincidsp.com X-Greylist: Sender succeeded STARTTLS authentication, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Fri, 31 Dec 2010 12:09:13 +0000 (UTC) diff --git a/drivers/serial/omapl_pru/Kconfig b/drivers/serial/omapl_pru/Kconfig new file mode 100644 index 0000000..f984bc5 --- /dev/null +++ b/drivers/serial/omapl_pru/Kconfig @@ -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. diff --git a/drivers/serial/omapl_pru/Makefile b/drivers/serial/omapl_pru/Makefile new file mode 100644 index 0000000..3378e0f --- /dev/null +++ b/drivers/serial/omapl_pru/Makefile @@ -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 diff --git a/drivers/serial/omapl_pru/omapl_suart_board.h b/drivers/serial/omapl_pru/omapl_suart_board.h new file mode 100644 index 0000000..0d29623 --- /dev/null +++ b/drivers/serial/omapl_pru/omapl_suart_board.h @@ -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_ */ diff --git a/drivers/serial/omapl_pru/suart_api.c b/drivers/serial/omapl_pru/suart_api.c new file mode 100644 index 0000000..c46d6b4 --- /dev/null +++ b/drivers/serial/omapl_pru/suart_api.c @@ -0,0 +1,2758 @@ +/* + * Copyright (C) 2010 Texas Instruments Incorporated + * Author: Jitendra Kumar + * + * 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 +#include +#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; +} diff --git a/drivers/serial/omapl_pru/suart_api.h b/drivers/serial/omapl_pru/suart_api.h new file mode 100644 index 0000000..3fb979e --- /dev/null +++ b/drivers/serial/omapl_pru/suart_api.h @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2010 Texas Instruments Incorporated + * Author: Jitendra Kumar + * + * 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 +#include +#include + +#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 diff --git a/drivers/serial/omapl_pru/suart_err.h b/drivers/serial/omapl_pru/suart_err.h new file mode 100644 index 0000000..ef114e3 --- /dev/null +++ b/drivers/serial/omapl_pru/suart_err.h @@ -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 diff --git a/drivers/serial/omapl_pru/suart_pru_regs.h b/drivers/serial/omapl_pru/suart_pru_regs.h new file mode 100644 index 0000000..393cf27 --- /dev/null +++ b/drivers/serial/omapl_pru/suart_pru_regs.h @@ -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 + +#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 diff --git a/drivers/serial/omapl_pru/suart_utils.c b/drivers/serial/omapl_pru/suart_utils.c new file mode 100644 index 0000000..5ea93f2 --- /dev/null +++ b/drivers/serial/omapl_pru/suart_utils.c @@ -0,0 +1,363 @@ +/* + * Copyright (C) 2010 Texas Instruments Incorporated + * Author: Jitendra Kumar + * + * 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 +#include +#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; +} diff --git a/drivers/serial/omapl_pru/suart_utils.h b/drivers/serial/omapl_pru/suart_utils.h new file mode 100644 index 0000000..64ec6c0 --- /dev/null +++ b/drivers/serial/omapl_pru/suart_utils.h @@ -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 + +/* ************ 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< + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(DRV_DESC);