11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver for AMBA serial ports 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 1999 ARM Limited 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2000 Deep Blue Solutions Ltd. 868b65f7305e54b822b2483c60de7d7b017526a92Russell King * Copyright (C) 2010 ST-Ericsson SA 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version. 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details. 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is a generic driver for ARM AMBA-type serial ports. They 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * have a lot of 16550-like features, but are not register compatible. 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that although they do have CTS, DCD and DSR inputs, they do 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not have an RI input, nor do they have DTR or RTS outputs. If 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * required, these have to be supplied via some other means (eg, GPIO) 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and hooked into this driver. 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined(CONFIG_SERIAL_AMBA_PL011_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SUPPORT_SYSRQ 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/console.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sysrq.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h> 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial_core.h> 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h> 46a62c80e559809e6c7851ec04d30575e85ad6f6edRussell King#include <linux/amba/bus.h> 47a62c80e559809e6c7851ec04d30575e85ad6f6edRussell King#include <linux/amba/serial.h> 48f8ce25476d5f12ffa29b885e49c38cd95053437eRussell King#include <linux/clk.h> 495a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 5068b65f7305e54b822b2483c60de7d7b017526a92Russell King#include <linux/dmaengine.h> 5168b65f7305e54b822b2483c60de7d7b017526a92Russell King#include <linux/dma-mapping.h> 5268b65f7305e54b822b2483c60de7d7b017526a92Russell King#include <linux/scatterlist.h> 53c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu#include <linux/delay.h> 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 56c6b8fdad144bbb915d124ffd95011ad55730bf9fRussell King#include <asm/sizes.h> 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_NR 14 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SERIAL_AMBA_MAJOR 204 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SERIAL_AMBA_MINOR 64 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SERIAL_AMBA_NR UART_NR 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AMBA_ISR_PASS_LIMIT 256 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66b63d4f0fb80918ab37b6c0ee1adcd49e05c9994cRussell King#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE) 67b63d4f0fb80918ab37b6c0ee1adcd49e05c9994cRussell King#define UART_DUMMY_DR_RX (1 << 16) 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 69c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu 70c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu#define UART_WA_SAVE_NR 14 71c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu 72c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahustatic void pl011_lockup_wa(unsigned long data); 73c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahustatic const u32 uart_wa_reg[UART_WA_SAVE_NR] = { 74c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu ST_UART011_DMAWM, 75c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu ST_UART011_TIMEOUT, 76c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu ST_UART011_LCRH_RX, 77c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu UART011_IBRD, 78c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu UART011_FBRD, 79c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu ST_UART011_LCRH_TX, 80c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu UART011_IFLS, 81c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu ST_UART011_XFCR, 82c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu ST_UART011_XON1, 83c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu ST_UART011_XON2, 84c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu ST_UART011_XOFF1, 85c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu ST_UART011_XOFF2, 86c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu UART011_CR, 87c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu UART011_IMSC 88c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu}; 89c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu 90c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahustatic u32 uart_wa_regdata[UART_WA_SAVE_NR]; 91c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahustatic DECLARE_TASKLET(pl011_lockup_tlet, pl011_lockup_wa, 0); 92c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu 935926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini/* There is by now at least one vendor with differing details, so handle it */ 945926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubinistruct vendor_data { 955926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini unsigned int ifls; 965926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini unsigned int fifosize; 97ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij unsigned int lcrh_tx; 98ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij unsigned int lcrh_rx; 99ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij bool oversampling; 100c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu bool interrupt_may_hang; /* vendor-specific */ 10138d624361b2a82d6317c379aebf81b1b28210bb0Russell King bool dma_threshold; 1025926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini}; 1035926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini 1045926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubinistatic struct vendor_data vendor_arm = { 1055926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, 1065926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini .fifosize = 16, 107ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij .lcrh_tx = UART011_LCRH, 108ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij .lcrh_rx = UART011_LCRH, 109ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij .oversampling = false, 11038d624361b2a82d6317c379aebf81b1b28210bb0Russell King .dma_threshold = false, 1115926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini}; 1125926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini 1135926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubinistatic struct vendor_data vendor_st = { 1145926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF, 1155926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini .fifosize = 64, 116ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij .lcrh_tx = ST_UART011_LCRH_TX, 117ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij .lcrh_rx = ST_UART011_LCRH_RX, 118ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij .oversampling = true, 119c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu .interrupt_may_hang = true, 12038d624361b2a82d6317c379aebf81b1b28210bb0Russell King .dma_threshold = true, 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 123c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahustatic struct uart_amba_port *amba_ports[UART_NR]; 124c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu 12568b65f7305e54b822b2483c60de7d7b017526a92Russell King/* Deals with DMA transactions */ 126ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 127ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstruct pl011_sgbuf { 128ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij struct scatterlist sg; 129ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij char *buf; 130ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij}; 131ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 132ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstruct pl011_dmarx_data { 133ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij struct dma_chan *chan; 134ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij struct completion complete; 135ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij bool use_buf_b; 136ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij struct pl011_sgbuf sgbuf_a; 137ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij struct pl011_sgbuf sgbuf_b; 138ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dma_cookie_t cookie; 139ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij bool running; 140ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij}; 141ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 14268b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstruct pl011_dmatx_data { 14368b65f7305e54b822b2483c60de7d7b017526a92Russell King struct dma_chan *chan; 14468b65f7305e54b822b2483c60de7d7b017526a92Russell King struct scatterlist sg; 14568b65f7305e54b822b2483c60de7d7b017526a92Russell King char *buf; 14668b65f7305e54b822b2483c60de7d7b017526a92Russell King bool queued; 14768b65f7305e54b822b2483c60de7d7b017526a92Russell King}; 14868b65f7305e54b822b2483c60de7d7b017526a92Russell King 149c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King/* 150c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King * We wrap our port structure around the generic uart_port. 151c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King */ 152c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell Kingstruct uart_amba_port { 153c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King struct uart_port port; 154c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King struct clk *clk; 155c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King const struct vendor_data *vendor; 15668b65f7305e54b822b2483c60de7d7b017526a92Russell King unsigned int dmacr; /* dma control reg */ 157c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King unsigned int im; /* interrupt mask */ 158c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King unsigned int old_status; 159ffca2b114c6a804d1307781df687e877a373a1c2Russell King unsigned int fifosize; /* vendor-specific */ 160c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King unsigned int lcrh_tx; /* vendor-specific */ 161c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King unsigned int lcrh_rx; /* vendor-specific */ 162d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu unsigned int old_cr; /* state during shutdown */ 163c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King bool autorts; 164c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King char type[12]; 165c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu bool interrupt_may_hang; /* vendor-specific */ 16668b65f7305e54b822b2483c60de7d7b017526a92Russell King#ifdef CONFIG_DMA_ENGINE 16768b65f7305e54b822b2483c60de7d7b017526a92Russell King /* DMA stuff */ 168ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij bool using_tx_dma; 169ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij bool using_rx_dma; 170ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij struct pl011_dmarx_data dmarx; 17168b65f7305e54b822b2483c60de7d7b017526a92Russell King struct pl011_dmatx_data dmatx; 17268b65f7305e54b822b2483c60de7d7b017526a92Russell King#endif 17368b65f7305e54b822b2483c60de7d7b017526a92Russell King}; 17468b65f7305e54b822b2483c60de7d7b017526a92Russell King 17568b65f7305e54b822b2483c60de7d7b017526a92Russell King/* 17629772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij * Reads up to 256 characters from the FIFO or until it's empty and 17729772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij * inserts them into the TTY layer. Returns the number of characters 17829772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij * read from the FIFO. 17929772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij */ 18029772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleijstatic int pl011_fifo_to_tty(struct uart_amba_port *uap) 18129772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij{ 18229772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij u16 status, ch; 18329772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij unsigned int flag, max_count = 256; 18429772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij int fifotaken = 0; 18529772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij 18629772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij while (max_count--) { 18729772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij status = readw(uap->port.membase + UART01x_FR); 18829772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij if (status & UART01x_FR_RXFE) 18929772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij break; 19029772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij 19129772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij /* Take chars from the FIFO and update status */ 19229772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij ch = readw(uap->port.membase + UART01x_DR) | 19329772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij UART_DUMMY_DR_RX; 19429772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij flag = TTY_NORMAL; 19529772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij uap->port.icount.rx++; 19629772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij fifotaken++; 19729772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij 19829772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij if (unlikely(ch & UART_DR_ERROR)) { 19929772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij if (ch & UART011_DR_BE) { 20029772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij ch &= ~(UART011_DR_FE | UART011_DR_PE); 20129772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij uap->port.icount.brk++; 20229772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij if (uart_handle_break(&uap->port)) 20329772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij continue; 20429772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij } else if (ch & UART011_DR_PE) 20529772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij uap->port.icount.parity++; 20629772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij else if (ch & UART011_DR_FE) 20729772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij uap->port.icount.frame++; 20829772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij if (ch & UART011_DR_OE) 20929772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij uap->port.icount.overrun++; 21029772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij 21129772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij ch &= uap->port.read_status_mask; 21229772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij 21329772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij if (ch & UART011_DR_BE) 21429772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij flag = TTY_BREAK; 21529772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij else if (ch & UART011_DR_PE) 21629772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij flag = TTY_PARITY; 21729772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij else if (ch & UART011_DR_FE) 21829772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij flag = TTY_FRAME; 21929772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij } 22029772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij 22129772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij if (uart_handle_sysrq_char(&uap->port, ch & 255)) 22229772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij continue; 22329772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij 22429772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag); 22529772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij } 22629772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij 22729772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij return fifotaken; 22829772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij} 22929772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij 23029772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij 23129772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij/* 23268b65f7305e54b822b2483c60de7d7b017526a92Russell King * All the DMA operation mode stuff goes inside this ifdef. 23368b65f7305e54b822b2483c60de7d7b017526a92Russell King * This assumes that you have a generic DMA device interface, 23468b65f7305e54b822b2483c60de7d7b017526a92Russell King * no custom DMA interfaces are supported. 23568b65f7305e54b822b2483c60de7d7b017526a92Russell King */ 23668b65f7305e54b822b2483c60de7d7b017526a92Russell King#ifdef CONFIG_DMA_ENGINE 23768b65f7305e54b822b2483c60de7d7b017526a92Russell King 23868b65f7305e54b822b2483c60de7d7b017526a92Russell King#define PL011_DMA_BUFFER_SIZE PAGE_SIZE 23968b65f7305e54b822b2483c60de7d7b017526a92Russell King 240ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic int pl011_sgbuf_init(struct dma_chan *chan, struct pl011_sgbuf *sg, 241ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij enum dma_data_direction dir) 242ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{ 243ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij sg->buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL); 244ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (!sg->buf) 245ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij return -ENOMEM; 246ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 247ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij sg_init_one(&sg->sg, sg->buf, PL011_DMA_BUFFER_SIZE); 248ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 249ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (dma_map_sg(chan->device->dev, &sg->sg, 1, dir) != 1) { 250ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij kfree(sg->buf); 251ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij return -EINVAL; 252ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij } 253ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij return 0; 254ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij} 255ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 256ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic void pl011_sgbuf_free(struct dma_chan *chan, struct pl011_sgbuf *sg, 257ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij enum dma_data_direction dir) 258ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{ 259ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (sg->buf) { 260ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dma_unmap_sg(chan->device->dev, &sg->sg, 1, dir); 261ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij kfree(sg->buf); 262ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij } 263ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij} 264ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 26568b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic void pl011_dma_probe_initcall(struct uart_amba_port *uap) 26668b65f7305e54b822b2483c60de7d7b017526a92Russell King{ 26768b65f7305e54b822b2483c60de7d7b017526a92Russell King /* DMA is the sole user of the platform data right now */ 26868b65f7305e54b822b2483c60de7d7b017526a92Russell King struct amba_pl011_data *plat = uap->port.dev->platform_data; 26968b65f7305e54b822b2483c60de7d7b017526a92Russell King struct dma_slave_config tx_conf = { 27068b65f7305e54b822b2483c60de7d7b017526a92Russell King .dst_addr = uap->port.mapbase + UART01x_DR, 27168b65f7305e54b822b2483c60de7d7b017526a92Russell King .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, 272a485df4b4404379786c4bdd258bc528b2617449dVinod Koul .direction = DMA_MEM_TO_DEV, 27368b65f7305e54b822b2483c60de7d7b017526a92Russell King .dst_maxburst = uap->fifosize >> 1, 27468b65f7305e54b822b2483c60de7d7b017526a92Russell King }; 27568b65f7305e54b822b2483c60de7d7b017526a92Russell King struct dma_chan *chan; 27668b65f7305e54b822b2483c60de7d7b017526a92Russell King dma_cap_mask_t mask; 27768b65f7305e54b822b2483c60de7d7b017526a92Russell King 27868b65f7305e54b822b2483c60de7d7b017526a92Russell King /* We need platform data */ 27968b65f7305e54b822b2483c60de7d7b017526a92Russell King if (!plat || !plat->dma_filter) { 28068b65f7305e54b822b2483c60de7d7b017526a92Russell King dev_info(uap->port.dev, "no DMA platform data\n"); 28168b65f7305e54b822b2483c60de7d7b017526a92Russell King return; 28268b65f7305e54b822b2483c60de7d7b017526a92Russell King } 28368b65f7305e54b822b2483c60de7d7b017526a92Russell King 284ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* Try to acquire a generic DMA engine slave TX channel */ 28568b65f7305e54b822b2483c60de7d7b017526a92Russell King dma_cap_zero(mask); 28668b65f7305e54b822b2483c60de7d7b017526a92Russell King dma_cap_set(DMA_SLAVE, mask); 28768b65f7305e54b822b2483c60de7d7b017526a92Russell King 28868b65f7305e54b822b2483c60de7d7b017526a92Russell King chan = dma_request_channel(mask, plat->dma_filter, plat->dma_tx_param); 28968b65f7305e54b822b2483c60de7d7b017526a92Russell King if (!chan) { 29068b65f7305e54b822b2483c60de7d7b017526a92Russell King dev_err(uap->port.dev, "no TX DMA channel!\n"); 29168b65f7305e54b822b2483c60de7d7b017526a92Russell King return; 29268b65f7305e54b822b2483c60de7d7b017526a92Russell King } 29368b65f7305e54b822b2483c60de7d7b017526a92Russell King 29468b65f7305e54b822b2483c60de7d7b017526a92Russell King dmaengine_slave_config(chan, &tx_conf); 29568b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->dmatx.chan = chan; 29668b65f7305e54b822b2483c60de7d7b017526a92Russell King 29768b65f7305e54b822b2483c60de7d7b017526a92Russell King dev_info(uap->port.dev, "DMA channel TX %s\n", 29868b65f7305e54b822b2483c60de7d7b017526a92Russell King dma_chan_name(uap->dmatx.chan)); 299ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 300ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* Optionally make use of an RX channel as well */ 301ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (plat->dma_rx_param) { 302ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij struct dma_slave_config rx_conf = { 303ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij .src_addr = uap->port.mapbase + UART01x_DR, 304ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, 305a485df4b4404379786c4bdd258bc528b2617449dVinod Koul .direction = DMA_DEV_TO_MEM, 306ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij .src_maxburst = uap->fifosize >> 1, 307ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij }; 308ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 309ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param); 310ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (!chan) { 311ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dev_err(uap->port.dev, "no RX DMA channel!\n"); 312ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij return; 313ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij } 314ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 315ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dmaengine_slave_config(chan, &rx_conf); 316ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij uap->dmarx.chan = chan; 317ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 318ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dev_info(uap->port.dev, "DMA channel RX %s\n", 319ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dma_chan_name(uap->dmarx.chan)); 320ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij } 32168b65f7305e54b822b2483c60de7d7b017526a92Russell King} 32268b65f7305e54b822b2483c60de7d7b017526a92Russell King 32368b65f7305e54b822b2483c60de7d7b017526a92Russell King#ifndef MODULE 32468b65f7305e54b822b2483c60de7d7b017526a92Russell King/* 32568b65f7305e54b822b2483c60de7d7b017526a92Russell King * Stack up the UARTs and let the above initcall be done at device 32668b65f7305e54b822b2483c60de7d7b017526a92Russell King * initcall time, because the serial driver is called as an arch 32768b65f7305e54b822b2483c60de7d7b017526a92Russell King * initcall, and at this time the DMA subsystem is not yet registered. 32868b65f7305e54b822b2483c60de7d7b017526a92Russell King * At this point the driver will switch over to using DMA where desired. 32968b65f7305e54b822b2483c60de7d7b017526a92Russell King */ 33068b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstruct dma_uap { 33168b65f7305e54b822b2483c60de7d7b017526a92Russell King struct list_head node; 33268b65f7305e54b822b2483c60de7d7b017526a92Russell King struct uart_amba_port *uap; 333c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King}; 334c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King 33568b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic LIST_HEAD(pl011_dma_uarts); 33668b65f7305e54b822b2483c60de7d7b017526a92Russell King 33768b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic int __init pl011_dma_initcall(void) 33868b65f7305e54b822b2483c60de7d7b017526a92Russell King{ 33968b65f7305e54b822b2483c60de7d7b017526a92Russell King struct list_head *node, *tmp; 34068b65f7305e54b822b2483c60de7d7b017526a92Russell King 34168b65f7305e54b822b2483c60de7d7b017526a92Russell King list_for_each_safe(node, tmp, &pl011_dma_uarts) { 34268b65f7305e54b822b2483c60de7d7b017526a92Russell King struct dma_uap *dmau = list_entry(node, struct dma_uap, node); 34368b65f7305e54b822b2483c60de7d7b017526a92Russell King pl011_dma_probe_initcall(dmau->uap); 34468b65f7305e54b822b2483c60de7d7b017526a92Russell King list_del(node); 34568b65f7305e54b822b2483c60de7d7b017526a92Russell King kfree(dmau); 34668b65f7305e54b822b2483c60de7d7b017526a92Russell King } 34768b65f7305e54b822b2483c60de7d7b017526a92Russell King return 0; 34868b65f7305e54b822b2483c60de7d7b017526a92Russell King} 34968b65f7305e54b822b2483c60de7d7b017526a92Russell King 35068b65f7305e54b822b2483c60de7d7b017526a92Russell Kingdevice_initcall(pl011_dma_initcall); 35168b65f7305e54b822b2483c60de7d7b017526a92Russell King 35268b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic void pl011_dma_probe(struct uart_amba_port *uap) 35368b65f7305e54b822b2483c60de7d7b017526a92Russell King{ 35468b65f7305e54b822b2483c60de7d7b017526a92Russell King struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL); 35568b65f7305e54b822b2483c60de7d7b017526a92Russell King if (dmau) { 35668b65f7305e54b822b2483c60de7d7b017526a92Russell King dmau->uap = uap; 35768b65f7305e54b822b2483c60de7d7b017526a92Russell King list_add_tail(&dmau->node, &pl011_dma_uarts); 35868b65f7305e54b822b2483c60de7d7b017526a92Russell King } 35968b65f7305e54b822b2483c60de7d7b017526a92Russell King} 36068b65f7305e54b822b2483c60de7d7b017526a92Russell King#else 36168b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic void pl011_dma_probe(struct uart_amba_port *uap) 36268b65f7305e54b822b2483c60de7d7b017526a92Russell King{ 36368b65f7305e54b822b2483c60de7d7b017526a92Russell King pl011_dma_probe_initcall(uap); 36468b65f7305e54b822b2483c60de7d7b017526a92Russell King} 36568b65f7305e54b822b2483c60de7d7b017526a92Russell King#endif 36668b65f7305e54b822b2483c60de7d7b017526a92Russell King 36768b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic void pl011_dma_remove(struct uart_amba_port *uap) 36868b65f7305e54b822b2483c60de7d7b017526a92Russell King{ 36968b65f7305e54b822b2483c60de7d7b017526a92Russell King /* TODO: remove the initcall if it has not yet executed */ 37068b65f7305e54b822b2483c60de7d7b017526a92Russell King if (uap->dmatx.chan) 37168b65f7305e54b822b2483c60de7d7b017526a92Russell King dma_release_channel(uap->dmatx.chan); 372ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (uap->dmarx.chan) 373ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dma_release_channel(uap->dmarx.chan); 37468b65f7305e54b822b2483c60de7d7b017526a92Russell King} 37568b65f7305e54b822b2483c60de7d7b017526a92Russell King 37668b65f7305e54b822b2483c60de7d7b017526a92Russell King/* Forward declare this for the refill routine */ 37768b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic int pl011_dma_tx_refill(struct uart_amba_port *uap); 37868b65f7305e54b822b2483c60de7d7b017526a92Russell King 37968b65f7305e54b822b2483c60de7d7b017526a92Russell King/* 38068b65f7305e54b822b2483c60de7d7b017526a92Russell King * The current DMA TX buffer has been sent. 38168b65f7305e54b822b2483c60de7d7b017526a92Russell King * Try to queue up another DMA buffer. 38268b65f7305e54b822b2483c60de7d7b017526a92Russell King */ 38368b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic void pl011_dma_tx_callback(void *data) 38468b65f7305e54b822b2483c60de7d7b017526a92Russell King{ 38568b65f7305e54b822b2483c60de7d7b017526a92Russell King struct uart_amba_port *uap = data; 38668b65f7305e54b822b2483c60de7d7b017526a92Russell King struct pl011_dmatx_data *dmatx = &uap->dmatx; 38768b65f7305e54b822b2483c60de7d7b017526a92Russell King unsigned long flags; 38868b65f7305e54b822b2483c60de7d7b017526a92Russell King u16 dmacr; 38968b65f7305e54b822b2483c60de7d7b017526a92Russell King 39068b65f7305e54b822b2483c60de7d7b017526a92Russell King spin_lock_irqsave(&uap->port.lock, flags); 39168b65f7305e54b822b2483c60de7d7b017526a92Russell King if (uap->dmatx.queued) 39268b65f7305e54b822b2483c60de7d7b017526a92Russell King dma_unmap_sg(dmatx->chan->device->dev, &dmatx->sg, 1, 39368b65f7305e54b822b2483c60de7d7b017526a92Russell King DMA_TO_DEVICE); 39468b65f7305e54b822b2483c60de7d7b017526a92Russell King 39568b65f7305e54b822b2483c60de7d7b017526a92Russell King dmacr = uap->dmacr; 39668b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->dmacr = dmacr & ~UART011_TXDMAE; 39768b65f7305e54b822b2483c60de7d7b017526a92Russell King writew(uap->dmacr, uap->port.membase + UART011_DMACR); 39868b65f7305e54b822b2483c60de7d7b017526a92Russell King 39968b65f7305e54b822b2483c60de7d7b017526a92Russell King /* 40068b65f7305e54b822b2483c60de7d7b017526a92Russell King * If TX DMA was disabled, it means that we've stopped the DMA for 40168b65f7305e54b822b2483c60de7d7b017526a92Russell King * some reason (eg, XOFF received, or we want to send an X-char.) 40268b65f7305e54b822b2483c60de7d7b017526a92Russell King * 40368b65f7305e54b822b2483c60de7d7b017526a92Russell King * Note: we need to be careful here of a potential race between DMA 40468b65f7305e54b822b2483c60de7d7b017526a92Russell King * and the rest of the driver - if the driver disables TX DMA while 40568b65f7305e54b822b2483c60de7d7b017526a92Russell King * a TX buffer completing, we must update the tx queued status to 40668b65f7305e54b822b2483c60de7d7b017526a92Russell King * get further refills (hence we check dmacr). 40768b65f7305e54b822b2483c60de7d7b017526a92Russell King */ 40868b65f7305e54b822b2483c60de7d7b017526a92Russell King if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) || 40968b65f7305e54b822b2483c60de7d7b017526a92Russell King uart_circ_empty(&uap->port.state->xmit)) { 41068b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->dmatx.queued = false; 41168b65f7305e54b822b2483c60de7d7b017526a92Russell King spin_unlock_irqrestore(&uap->port.lock, flags); 41268b65f7305e54b822b2483c60de7d7b017526a92Russell King return; 41368b65f7305e54b822b2483c60de7d7b017526a92Russell King } 41468b65f7305e54b822b2483c60de7d7b017526a92Russell King 41568b65f7305e54b822b2483c60de7d7b017526a92Russell King if (pl011_dma_tx_refill(uap) <= 0) { 41668b65f7305e54b822b2483c60de7d7b017526a92Russell King /* 41768b65f7305e54b822b2483c60de7d7b017526a92Russell King * We didn't queue a DMA buffer for some reason, but we 41868b65f7305e54b822b2483c60de7d7b017526a92Russell King * have data pending to be sent. Re-enable the TX IRQ. 41968b65f7305e54b822b2483c60de7d7b017526a92Russell King */ 42068b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->im |= UART011_TXIM; 42168b65f7305e54b822b2483c60de7d7b017526a92Russell King writew(uap->im, uap->port.membase + UART011_IMSC); 42268b65f7305e54b822b2483c60de7d7b017526a92Russell King } 42368b65f7305e54b822b2483c60de7d7b017526a92Russell King spin_unlock_irqrestore(&uap->port.lock, flags); 42468b65f7305e54b822b2483c60de7d7b017526a92Russell King} 42568b65f7305e54b822b2483c60de7d7b017526a92Russell King 42668b65f7305e54b822b2483c60de7d7b017526a92Russell King/* 42768b65f7305e54b822b2483c60de7d7b017526a92Russell King * Try to refill the TX DMA buffer. 42868b65f7305e54b822b2483c60de7d7b017526a92Russell King * Locking: called with port lock held and IRQs disabled. 42968b65f7305e54b822b2483c60de7d7b017526a92Russell King * Returns: 43068b65f7305e54b822b2483c60de7d7b017526a92Russell King * 1 if we queued up a TX DMA buffer. 43168b65f7305e54b822b2483c60de7d7b017526a92Russell King * 0 if we didn't want to handle this by DMA 43268b65f7305e54b822b2483c60de7d7b017526a92Russell King * <0 on error 43368b65f7305e54b822b2483c60de7d7b017526a92Russell King */ 43468b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic int pl011_dma_tx_refill(struct uart_amba_port *uap) 43568b65f7305e54b822b2483c60de7d7b017526a92Russell King{ 43668b65f7305e54b822b2483c60de7d7b017526a92Russell King struct pl011_dmatx_data *dmatx = &uap->dmatx; 43768b65f7305e54b822b2483c60de7d7b017526a92Russell King struct dma_chan *chan = dmatx->chan; 43868b65f7305e54b822b2483c60de7d7b017526a92Russell King struct dma_device *dma_dev = chan->device; 43968b65f7305e54b822b2483c60de7d7b017526a92Russell King struct dma_async_tx_descriptor *desc; 44068b65f7305e54b822b2483c60de7d7b017526a92Russell King struct circ_buf *xmit = &uap->port.state->xmit; 44168b65f7305e54b822b2483c60de7d7b017526a92Russell King unsigned int count; 44268b65f7305e54b822b2483c60de7d7b017526a92Russell King 44368b65f7305e54b822b2483c60de7d7b017526a92Russell King /* 44468b65f7305e54b822b2483c60de7d7b017526a92Russell King * Try to avoid the overhead involved in using DMA if the 44568b65f7305e54b822b2483c60de7d7b017526a92Russell King * transaction fits in the first half of the FIFO, by using 44668b65f7305e54b822b2483c60de7d7b017526a92Russell King * the standard interrupt handling. This ensures that we 44768b65f7305e54b822b2483c60de7d7b017526a92Russell King * issue a uart_write_wakeup() at the appropriate time. 44868b65f7305e54b822b2483c60de7d7b017526a92Russell King */ 44968b65f7305e54b822b2483c60de7d7b017526a92Russell King count = uart_circ_chars_pending(xmit); 45068b65f7305e54b822b2483c60de7d7b017526a92Russell King if (count < (uap->fifosize >> 1)) { 45168b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->dmatx.queued = false; 45268b65f7305e54b822b2483c60de7d7b017526a92Russell King return 0; 45368b65f7305e54b822b2483c60de7d7b017526a92Russell King } 45468b65f7305e54b822b2483c60de7d7b017526a92Russell King 45568b65f7305e54b822b2483c60de7d7b017526a92Russell King /* 45668b65f7305e54b822b2483c60de7d7b017526a92Russell King * Bodge: don't send the last character by DMA, as this 45768b65f7305e54b822b2483c60de7d7b017526a92Russell King * will prevent XON from notifying us to restart DMA. 45868b65f7305e54b822b2483c60de7d7b017526a92Russell King */ 45968b65f7305e54b822b2483c60de7d7b017526a92Russell King count -= 1; 46068b65f7305e54b822b2483c60de7d7b017526a92Russell King 46168b65f7305e54b822b2483c60de7d7b017526a92Russell King /* Else proceed to copy the TX chars to the DMA buffer and fire DMA */ 46268b65f7305e54b822b2483c60de7d7b017526a92Russell King if (count > PL011_DMA_BUFFER_SIZE) 46368b65f7305e54b822b2483c60de7d7b017526a92Russell King count = PL011_DMA_BUFFER_SIZE; 46468b65f7305e54b822b2483c60de7d7b017526a92Russell King 46568b65f7305e54b822b2483c60de7d7b017526a92Russell King if (xmit->tail < xmit->head) 46668b65f7305e54b822b2483c60de7d7b017526a92Russell King memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count); 46768b65f7305e54b822b2483c60de7d7b017526a92Russell King else { 46868b65f7305e54b822b2483c60de7d7b017526a92Russell King size_t first = UART_XMIT_SIZE - xmit->tail; 46968b65f7305e54b822b2483c60de7d7b017526a92Russell King size_t second = xmit->head; 47068b65f7305e54b822b2483c60de7d7b017526a92Russell King 47168b65f7305e54b822b2483c60de7d7b017526a92Russell King memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], first); 47268b65f7305e54b822b2483c60de7d7b017526a92Russell King if (second) 47368b65f7305e54b822b2483c60de7d7b017526a92Russell King memcpy(&dmatx->buf[first], &xmit->buf[0], second); 47468b65f7305e54b822b2483c60de7d7b017526a92Russell King } 47568b65f7305e54b822b2483c60de7d7b017526a92Russell King 47668b65f7305e54b822b2483c60de7d7b017526a92Russell King dmatx->sg.length = count; 47768b65f7305e54b822b2483c60de7d7b017526a92Russell King 47868b65f7305e54b822b2483c60de7d7b017526a92Russell King if (dma_map_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE) != 1) { 47968b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->dmatx.queued = false; 48068b65f7305e54b822b2483c60de7d7b017526a92Russell King dev_dbg(uap->port.dev, "unable to map TX DMA\n"); 48168b65f7305e54b822b2483c60de7d7b017526a92Russell King return -EBUSY; 48268b65f7305e54b822b2483c60de7d7b017526a92Russell King } 48368b65f7305e54b822b2483c60de7d7b017526a92Russell King 484a485df4b4404379786c4bdd258bc528b2617449dVinod Koul desc = dma_dev->device_prep_slave_sg(chan, &dmatx->sg, 1, DMA_MEM_TO_DEV, 48568b65f7305e54b822b2483c60de7d7b017526a92Russell King DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 48668b65f7305e54b822b2483c60de7d7b017526a92Russell King if (!desc) { 48768b65f7305e54b822b2483c60de7d7b017526a92Russell King dma_unmap_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE); 48868b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->dmatx.queued = false; 48968b65f7305e54b822b2483c60de7d7b017526a92Russell King /* 49068b65f7305e54b822b2483c60de7d7b017526a92Russell King * If DMA cannot be used right now, we complete this 49168b65f7305e54b822b2483c60de7d7b017526a92Russell King * transaction via IRQ and let the TTY layer retry. 49268b65f7305e54b822b2483c60de7d7b017526a92Russell King */ 49368b65f7305e54b822b2483c60de7d7b017526a92Russell King dev_dbg(uap->port.dev, "TX DMA busy\n"); 49468b65f7305e54b822b2483c60de7d7b017526a92Russell King return -EBUSY; 49568b65f7305e54b822b2483c60de7d7b017526a92Russell King } 49668b65f7305e54b822b2483c60de7d7b017526a92Russell King 49768b65f7305e54b822b2483c60de7d7b017526a92Russell King /* Some data to go along to the callback */ 49868b65f7305e54b822b2483c60de7d7b017526a92Russell King desc->callback = pl011_dma_tx_callback; 49968b65f7305e54b822b2483c60de7d7b017526a92Russell King desc->callback_param = uap; 50068b65f7305e54b822b2483c60de7d7b017526a92Russell King 50168b65f7305e54b822b2483c60de7d7b017526a92Russell King /* All errors should happen at prepare time */ 50268b65f7305e54b822b2483c60de7d7b017526a92Russell King dmaengine_submit(desc); 50368b65f7305e54b822b2483c60de7d7b017526a92Russell King 50468b65f7305e54b822b2483c60de7d7b017526a92Russell King /* Fire the DMA transaction */ 50568b65f7305e54b822b2483c60de7d7b017526a92Russell King dma_dev->device_issue_pending(chan); 50668b65f7305e54b822b2483c60de7d7b017526a92Russell King 50768b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->dmacr |= UART011_TXDMAE; 50868b65f7305e54b822b2483c60de7d7b017526a92Russell King writew(uap->dmacr, uap->port.membase + UART011_DMACR); 50968b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->dmatx.queued = true; 51068b65f7305e54b822b2483c60de7d7b017526a92Russell King 51168b65f7305e54b822b2483c60de7d7b017526a92Russell King /* 51268b65f7305e54b822b2483c60de7d7b017526a92Russell King * Now we know that DMA will fire, so advance the ring buffer 51368b65f7305e54b822b2483c60de7d7b017526a92Russell King * with the stuff we just dispatched. 51468b65f7305e54b822b2483c60de7d7b017526a92Russell King */ 51568b65f7305e54b822b2483c60de7d7b017526a92Russell King xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); 51668b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->port.icount.tx += count; 51768b65f7305e54b822b2483c60de7d7b017526a92Russell King 51868b65f7305e54b822b2483c60de7d7b017526a92Russell King if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 51968b65f7305e54b822b2483c60de7d7b017526a92Russell King uart_write_wakeup(&uap->port); 52068b65f7305e54b822b2483c60de7d7b017526a92Russell King 52168b65f7305e54b822b2483c60de7d7b017526a92Russell King return 1; 52268b65f7305e54b822b2483c60de7d7b017526a92Russell King} 52368b65f7305e54b822b2483c60de7d7b017526a92Russell King 52468b65f7305e54b822b2483c60de7d7b017526a92Russell King/* 52568b65f7305e54b822b2483c60de7d7b017526a92Russell King * We received a transmit interrupt without a pending X-char but with 52668b65f7305e54b822b2483c60de7d7b017526a92Russell King * pending characters. 52768b65f7305e54b822b2483c60de7d7b017526a92Russell King * Locking: called with port lock held and IRQs disabled. 52868b65f7305e54b822b2483c60de7d7b017526a92Russell King * Returns: 52968b65f7305e54b822b2483c60de7d7b017526a92Russell King * false if we want to use PIO to transmit 53068b65f7305e54b822b2483c60de7d7b017526a92Russell King * true if we queued a DMA buffer 53168b65f7305e54b822b2483c60de7d7b017526a92Russell King */ 53268b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic bool pl011_dma_tx_irq(struct uart_amba_port *uap) 53368b65f7305e54b822b2483c60de7d7b017526a92Russell King{ 534ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (!uap->using_tx_dma) 53568b65f7305e54b822b2483c60de7d7b017526a92Russell King return false; 53668b65f7305e54b822b2483c60de7d7b017526a92Russell King 53768b65f7305e54b822b2483c60de7d7b017526a92Russell King /* 53868b65f7305e54b822b2483c60de7d7b017526a92Russell King * If we already have a TX buffer queued, but received a 53968b65f7305e54b822b2483c60de7d7b017526a92Russell King * TX interrupt, it will be because we've just sent an X-char. 54068b65f7305e54b822b2483c60de7d7b017526a92Russell King * Ensure the TX DMA is enabled and the TX IRQ is disabled. 54168b65f7305e54b822b2483c60de7d7b017526a92Russell King */ 54268b65f7305e54b822b2483c60de7d7b017526a92Russell King if (uap->dmatx.queued) { 54368b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->dmacr |= UART011_TXDMAE; 54468b65f7305e54b822b2483c60de7d7b017526a92Russell King writew(uap->dmacr, uap->port.membase + UART011_DMACR); 54568b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->im &= ~UART011_TXIM; 54668b65f7305e54b822b2483c60de7d7b017526a92Russell King writew(uap->im, uap->port.membase + UART011_IMSC); 54768b65f7305e54b822b2483c60de7d7b017526a92Russell King return true; 54868b65f7305e54b822b2483c60de7d7b017526a92Russell King } 54968b65f7305e54b822b2483c60de7d7b017526a92Russell King 55068b65f7305e54b822b2483c60de7d7b017526a92Russell King /* 55168b65f7305e54b822b2483c60de7d7b017526a92Russell King * We don't have a TX buffer queued, so try to queue one. 55225985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * If we successfully queued a buffer, mask the TX IRQ. 55368b65f7305e54b822b2483c60de7d7b017526a92Russell King */ 55468b65f7305e54b822b2483c60de7d7b017526a92Russell King if (pl011_dma_tx_refill(uap) > 0) { 55568b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->im &= ~UART011_TXIM; 55668b65f7305e54b822b2483c60de7d7b017526a92Russell King writew(uap->im, uap->port.membase + UART011_IMSC); 55768b65f7305e54b822b2483c60de7d7b017526a92Russell King return true; 55868b65f7305e54b822b2483c60de7d7b017526a92Russell King } 55968b65f7305e54b822b2483c60de7d7b017526a92Russell King return false; 56068b65f7305e54b822b2483c60de7d7b017526a92Russell King} 56168b65f7305e54b822b2483c60de7d7b017526a92Russell King 56268b65f7305e54b822b2483c60de7d7b017526a92Russell King/* 56368b65f7305e54b822b2483c60de7d7b017526a92Russell King * Stop the DMA transmit (eg, due to received XOFF). 56468b65f7305e54b822b2483c60de7d7b017526a92Russell King * Locking: called with port lock held and IRQs disabled. 56568b65f7305e54b822b2483c60de7d7b017526a92Russell King */ 56668b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic inline void pl011_dma_tx_stop(struct uart_amba_port *uap) 56768b65f7305e54b822b2483c60de7d7b017526a92Russell King{ 56868b65f7305e54b822b2483c60de7d7b017526a92Russell King if (uap->dmatx.queued) { 56968b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->dmacr &= ~UART011_TXDMAE; 57068b65f7305e54b822b2483c60de7d7b017526a92Russell King writew(uap->dmacr, uap->port.membase + UART011_DMACR); 57168b65f7305e54b822b2483c60de7d7b017526a92Russell King } 57268b65f7305e54b822b2483c60de7d7b017526a92Russell King} 57368b65f7305e54b822b2483c60de7d7b017526a92Russell King 57468b65f7305e54b822b2483c60de7d7b017526a92Russell King/* 57568b65f7305e54b822b2483c60de7d7b017526a92Russell King * Try to start a DMA transmit, or in the case of an XON/OFF 57668b65f7305e54b822b2483c60de7d7b017526a92Russell King * character queued for send, try to get that character out ASAP. 57768b65f7305e54b822b2483c60de7d7b017526a92Russell King * Locking: called with port lock held and IRQs disabled. 57868b65f7305e54b822b2483c60de7d7b017526a92Russell King * Returns: 57968b65f7305e54b822b2483c60de7d7b017526a92Russell King * false if we want the TX IRQ to be enabled 58068b65f7305e54b822b2483c60de7d7b017526a92Russell King * true if we have a buffer queued 58168b65f7305e54b822b2483c60de7d7b017526a92Russell King */ 58268b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic inline bool pl011_dma_tx_start(struct uart_amba_port *uap) 58368b65f7305e54b822b2483c60de7d7b017526a92Russell King{ 58468b65f7305e54b822b2483c60de7d7b017526a92Russell King u16 dmacr; 58568b65f7305e54b822b2483c60de7d7b017526a92Russell King 586ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (!uap->using_tx_dma) 58768b65f7305e54b822b2483c60de7d7b017526a92Russell King return false; 58868b65f7305e54b822b2483c60de7d7b017526a92Russell King 58968b65f7305e54b822b2483c60de7d7b017526a92Russell King if (!uap->port.x_char) { 59068b65f7305e54b822b2483c60de7d7b017526a92Russell King /* no X-char, try to push chars out in DMA mode */ 59168b65f7305e54b822b2483c60de7d7b017526a92Russell King bool ret = true; 59268b65f7305e54b822b2483c60de7d7b017526a92Russell King 59368b65f7305e54b822b2483c60de7d7b017526a92Russell King if (!uap->dmatx.queued) { 59468b65f7305e54b822b2483c60de7d7b017526a92Russell King if (pl011_dma_tx_refill(uap) > 0) { 59568b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->im &= ~UART011_TXIM; 59668b65f7305e54b822b2483c60de7d7b017526a92Russell King ret = true; 59768b65f7305e54b822b2483c60de7d7b017526a92Russell King } else { 59868b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->im |= UART011_TXIM; 59968b65f7305e54b822b2483c60de7d7b017526a92Russell King ret = false; 60068b65f7305e54b822b2483c60de7d7b017526a92Russell King } 60168b65f7305e54b822b2483c60de7d7b017526a92Russell King writew(uap->im, uap->port.membase + UART011_IMSC); 60268b65f7305e54b822b2483c60de7d7b017526a92Russell King } else if (!(uap->dmacr & UART011_TXDMAE)) { 60368b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->dmacr |= UART011_TXDMAE; 60468b65f7305e54b822b2483c60de7d7b017526a92Russell King writew(uap->dmacr, 60568b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->port.membase + UART011_DMACR); 60668b65f7305e54b822b2483c60de7d7b017526a92Russell King } 60768b65f7305e54b822b2483c60de7d7b017526a92Russell King return ret; 60868b65f7305e54b822b2483c60de7d7b017526a92Russell King } 60968b65f7305e54b822b2483c60de7d7b017526a92Russell King 61068b65f7305e54b822b2483c60de7d7b017526a92Russell King /* 61168b65f7305e54b822b2483c60de7d7b017526a92Russell King * We have an X-char to send. Disable DMA to prevent it loading 61268b65f7305e54b822b2483c60de7d7b017526a92Russell King * the TX fifo, and then see if we can stuff it into the FIFO. 61368b65f7305e54b822b2483c60de7d7b017526a92Russell King */ 61468b65f7305e54b822b2483c60de7d7b017526a92Russell King dmacr = uap->dmacr; 61568b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->dmacr &= ~UART011_TXDMAE; 61668b65f7305e54b822b2483c60de7d7b017526a92Russell King writew(uap->dmacr, uap->port.membase + UART011_DMACR); 61768b65f7305e54b822b2483c60de7d7b017526a92Russell King 61868b65f7305e54b822b2483c60de7d7b017526a92Russell King if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) { 61968b65f7305e54b822b2483c60de7d7b017526a92Russell King /* 62068b65f7305e54b822b2483c60de7d7b017526a92Russell King * No space in the FIFO, so enable the transmit interrupt 62168b65f7305e54b822b2483c60de7d7b017526a92Russell King * so we know when there is space. Note that once we've 62268b65f7305e54b822b2483c60de7d7b017526a92Russell King * loaded the character, we should just re-enable DMA. 62368b65f7305e54b822b2483c60de7d7b017526a92Russell King */ 62468b65f7305e54b822b2483c60de7d7b017526a92Russell King return false; 62568b65f7305e54b822b2483c60de7d7b017526a92Russell King } 62668b65f7305e54b822b2483c60de7d7b017526a92Russell King 62768b65f7305e54b822b2483c60de7d7b017526a92Russell King writew(uap->port.x_char, uap->port.membase + UART01x_DR); 62868b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->port.icount.tx++; 62968b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->port.x_char = 0; 63068b65f7305e54b822b2483c60de7d7b017526a92Russell King 63168b65f7305e54b822b2483c60de7d7b017526a92Russell King /* Success - restore the DMA state */ 63268b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->dmacr = dmacr; 63368b65f7305e54b822b2483c60de7d7b017526a92Russell King writew(dmacr, uap->port.membase + UART011_DMACR); 63468b65f7305e54b822b2483c60de7d7b017526a92Russell King 63568b65f7305e54b822b2483c60de7d7b017526a92Russell King return true; 63668b65f7305e54b822b2483c60de7d7b017526a92Russell King} 63768b65f7305e54b822b2483c60de7d7b017526a92Russell King 63868b65f7305e54b822b2483c60de7d7b017526a92Russell King/* 63968b65f7305e54b822b2483c60de7d7b017526a92Russell King * Flush the transmit buffer. 64068b65f7305e54b822b2483c60de7d7b017526a92Russell King * Locking: called with port lock held and IRQs disabled. 64168b65f7305e54b822b2483c60de7d7b017526a92Russell King */ 64268b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic void pl011_dma_flush_buffer(struct uart_port *port) 64368b65f7305e54b822b2483c60de7d7b017526a92Russell King{ 64468b65f7305e54b822b2483c60de7d7b017526a92Russell King struct uart_amba_port *uap = (struct uart_amba_port *)port; 64568b65f7305e54b822b2483c60de7d7b017526a92Russell King 646ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (!uap->using_tx_dma) 64768b65f7305e54b822b2483c60de7d7b017526a92Russell King return; 64868b65f7305e54b822b2483c60de7d7b017526a92Russell King 64968b65f7305e54b822b2483c60de7d7b017526a92Russell King /* Avoid deadlock with the DMA engine callback */ 65068b65f7305e54b822b2483c60de7d7b017526a92Russell King spin_unlock(&uap->port.lock); 65168b65f7305e54b822b2483c60de7d7b017526a92Russell King dmaengine_terminate_all(uap->dmatx.chan); 65268b65f7305e54b822b2483c60de7d7b017526a92Russell King spin_lock(&uap->port.lock); 65368b65f7305e54b822b2483c60de7d7b017526a92Russell King if (uap->dmatx.queued) { 65468b65f7305e54b822b2483c60de7d7b017526a92Russell King dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1, 65568b65f7305e54b822b2483c60de7d7b017526a92Russell King DMA_TO_DEVICE); 65668b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->dmatx.queued = false; 65768b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->dmacr &= ~UART011_TXDMAE; 65868b65f7305e54b822b2483c60de7d7b017526a92Russell King writew(uap->dmacr, uap->port.membase + UART011_DMACR); 65968b65f7305e54b822b2483c60de7d7b017526a92Russell King } 66068b65f7305e54b822b2483c60de7d7b017526a92Russell King} 66168b65f7305e54b822b2483c60de7d7b017526a92Russell King 662ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic void pl011_dma_rx_callback(void *data); 663ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 664ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap) 665ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{ 666ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij struct dma_chan *rxchan = uap->dmarx.chan; 667ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij struct dma_device *dma_dev; 668ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij struct pl011_dmarx_data *dmarx = &uap->dmarx; 669ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij struct dma_async_tx_descriptor *desc; 670ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij struct pl011_sgbuf *sgbuf; 671ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 672ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (!rxchan) 673ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij return -EIO; 674ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 675ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* Start the RX DMA job */ 676ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij sgbuf = uap->dmarx.use_buf_b ? 677ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij &uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a; 678ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dma_dev = rxchan->device; 679ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij desc = rxchan->device->device_prep_slave_sg(rxchan, &sgbuf->sg, 1, 680a485df4b4404379786c4bdd258bc528b2617449dVinod Koul DMA_DEV_TO_MEM, 681ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 682ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* 683ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * If the DMA engine is busy and cannot prepare a 684ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * channel, no big deal, the driver will fall back 685ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * to interrupt mode as a result of this error code. 686ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij */ 687ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (!desc) { 688ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij uap->dmarx.running = false; 689ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dmaengine_terminate_all(rxchan); 690ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij return -EBUSY; 691ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij } 692ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 693ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* Some data to go along to the callback */ 694ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij desc->callback = pl011_dma_rx_callback; 695ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij desc->callback_param = uap; 696ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dmarx->cookie = dmaengine_submit(desc); 697ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dma_async_issue_pending(rxchan); 698ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 699ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij uap->dmacr |= UART011_RXDMAE; 700ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij writew(uap->dmacr, uap->port.membase + UART011_DMACR); 701ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij uap->dmarx.running = true; 702ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 703ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij uap->im &= ~UART011_RXIM; 704ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij writew(uap->im, uap->port.membase + UART011_IMSC); 705ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 706ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij return 0; 707ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij} 708ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 709ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij/* 710ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * This is called when either the DMA job is complete, or 711ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * the FIFO timeout interrupt occurred. This must be called 712ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * with the port spinlock uap->port.lock held. 713ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij */ 714ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic void pl011_dma_rx_chars(struct uart_amba_port *uap, 715ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij u32 pending, bool use_buf_b, 716ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij bool readfifo) 717ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{ 718ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij struct tty_struct *tty = uap->port.state->port.tty; 719ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij struct pl011_sgbuf *sgbuf = use_buf_b ? 720ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij &uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a; 721ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij struct device *dev = uap->dmarx.chan->device->dev; 722ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij int dma_count = 0; 723ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij u32 fifotaken = 0; /* only used for vdbg() */ 724ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 725ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* Pick everything from the DMA first */ 726ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (pending) { 727ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* Sync in buffer */ 728ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dma_sync_sg_for_cpu(dev, &sgbuf->sg, 1, DMA_FROM_DEVICE); 729ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 730ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* 731ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * First take all chars in the DMA pipe, then look in the FIFO. 732ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * Note that tty_insert_flip_buf() tries to take as many chars 733ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * as it can. 734ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij */ 735ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dma_count = tty_insert_flip_string(uap->port.state->port.tty, 736ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij sgbuf->buf, pending); 737ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 738ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* Return buffer to device */ 739ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dma_sync_sg_for_device(dev, &sgbuf->sg, 1, DMA_FROM_DEVICE); 740ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 741ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij uap->port.icount.rx += dma_count; 742ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (dma_count < pending) 743ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dev_warn(uap->port.dev, 744ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij "couldn't insert all characters (TTY is full?)\n"); 745ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij } 746ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 747ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* 748ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * Only continue with trying to read the FIFO if all DMA chars have 749ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * been taken first. 750ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij */ 751ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (dma_count == pending && readfifo) { 752ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* Clear any error flags */ 753ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS, 754ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij uap->port.membase + UART011_ICR); 755ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 756ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* 757ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * If we read all the DMA'd characters, and we had an 75829772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij * incomplete buffer, that could be due to an rx error, or 75929772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij * maybe we just timed out. Read any pending chars and check 76029772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij * the error status. 76129772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij * 76229772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij * Error conditions will only occur in the FIFO, these will 76329772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij * trigger an immediate interrupt and stop the DMA job, so we 76429772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij * will always find the error in the FIFO, never in the DMA 76529772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij * buffer. 766ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij */ 76729772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij fifotaken = pl011_fifo_to_tty(uap); 768ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij } 769ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 770ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij spin_unlock(&uap->port.lock); 771ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dev_vdbg(uap->port.dev, 772ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij "Took %d chars from DMA buffer and %d chars from the FIFO\n", 773ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dma_count, fifotaken); 774ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij tty_flip_buffer_push(tty); 775ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij spin_lock(&uap->port.lock); 776ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij} 777ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 778ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic void pl011_dma_rx_irq(struct uart_amba_port *uap) 779ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{ 780ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij struct pl011_dmarx_data *dmarx = &uap->dmarx; 781ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij struct dma_chan *rxchan = dmarx->chan; 782ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij struct pl011_sgbuf *sgbuf = dmarx->use_buf_b ? 783ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij &dmarx->sgbuf_b : &dmarx->sgbuf_a; 784ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij size_t pending; 785ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij struct dma_tx_state state; 786ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij enum dma_status dmastat; 787ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 788ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* 789ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * Pause the transfer so we can trust the current counter, 790ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * do this before we pause the PL011 block, else we may 791ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * overflow the FIFO. 792ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij */ 793ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (dmaengine_pause(rxchan)) 794ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dev_err(uap->port.dev, "unable to pause DMA transfer\n"); 795ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dmastat = rxchan->device->device_tx_status(rxchan, 796ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dmarx->cookie, &state); 797ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (dmastat != DMA_PAUSED) 798ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dev_err(uap->port.dev, "unable to pause DMA transfer\n"); 799ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 800ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* Disable RX DMA - incoming data will wait in the FIFO */ 801ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij uap->dmacr &= ~UART011_RXDMAE; 802ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij writew(uap->dmacr, uap->port.membase + UART011_DMACR); 803ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij uap->dmarx.running = false; 804ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 805ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij pending = sgbuf->sg.length - state.residue; 806ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij BUG_ON(pending > PL011_DMA_BUFFER_SIZE); 807ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* Then we terminate the transfer - we now know our residue */ 808ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dmaengine_terminate_all(rxchan); 809ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 810ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* 811ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * This will take the chars we have so far and insert 812ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * into the framework. 813ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij */ 814ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij pl011_dma_rx_chars(uap, pending, dmarx->use_buf_b, true); 815ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 816ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* Switch buffer & re-trigger DMA job */ 817ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dmarx->use_buf_b = !dmarx->use_buf_b; 818ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (pl011_dma_rx_trigger_dma(uap)) { 819ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dev_dbg(uap->port.dev, "could not retrigger RX DMA job " 820ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij "fall back to interrupt mode\n"); 821ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij uap->im |= UART011_RXIM; 822ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij writew(uap->im, uap->port.membase + UART011_IMSC); 823ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij } 824ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij} 825ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 826ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic void pl011_dma_rx_callback(void *data) 827ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{ 828ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij struct uart_amba_port *uap = data; 829ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij struct pl011_dmarx_data *dmarx = &uap->dmarx; 830ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij bool lastbuf = dmarx->use_buf_b; 831ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij int ret; 832ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 833ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* 834ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * This completion interrupt occurs typically when the 835ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * RX buffer is totally stuffed but no timeout has yet 836ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * occurred. When that happens, we just want the RX 837ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * routine to flush out the secondary DMA buffer while 838ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * we immediately trigger the next DMA job. 839ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij */ 840ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij spin_lock_irq(&uap->port.lock); 841ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij uap->dmarx.running = false; 842ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dmarx->use_buf_b = !lastbuf; 843ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij ret = pl011_dma_rx_trigger_dma(uap); 844ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 845ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij pl011_dma_rx_chars(uap, PL011_DMA_BUFFER_SIZE, lastbuf, false); 846ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij spin_unlock_irq(&uap->port.lock); 847ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* 848ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * Do this check after we picked the DMA chars so we don't 849ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * get some IRQ immediately from RX. 850ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij */ 851ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (ret) { 852ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dev_dbg(uap->port.dev, "could not retrigger RX DMA job " 853ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij "fall back to interrupt mode\n"); 854ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij uap->im |= UART011_RXIM; 855ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij writew(uap->im, uap->port.membase + UART011_IMSC); 856ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij } 857ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij} 858ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 859ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij/* 860ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * Stop accepting received characters, when we're shutting down or 861ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * suspending this port. 862ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * Locking: called with port lock held and IRQs disabled. 863ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij */ 864ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic inline void pl011_dma_rx_stop(struct uart_amba_port *uap) 865ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{ 866ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* FIXME. Just disable the DMA enable */ 867ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij uap->dmacr &= ~UART011_RXDMAE; 868ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij writew(uap->dmacr, uap->port.membase + UART011_DMACR); 869ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij} 87068b65f7305e54b822b2483c60de7d7b017526a92Russell King 87168b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic void pl011_dma_startup(struct uart_amba_port *uap) 87268b65f7305e54b822b2483c60de7d7b017526a92Russell King{ 873ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij int ret; 874ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 87568b65f7305e54b822b2483c60de7d7b017526a92Russell King if (!uap->dmatx.chan) 87668b65f7305e54b822b2483c60de7d7b017526a92Russell King return; 87768b65f7305e54b822b2483c60de7d7b017526a92Russell King 87868b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL); 87968b65f7305e54b822b2483c60de7d7b017526a92Russell King if (!uap->dmatx.buf) { 88068b65f7305e54b822b2483c60de7d7b017526a92Russell King dev_err(uap->port.dev, "no memory for DMA TX buffer\n"); 88168b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->port.fifosize = uap->fifosize; 88268b65f7305e54b822b2483c60de7d7b017526a92Russell King return; 88368b65f7305e54b822b2483c60de7d7b017526a92Russell King } 88468b65f7305e54b822b2483c60de7d7b017526a92Russell King 88568b65f7305e54b822b2483c60de7d7b017526a92Russell King sg_init_one(&uap->dmatx.sg, uap->dmatx.buf, PL011_DMA_BUFFER_SIZE); 88668b65f7305e54b822b2483c60de7d7b017526a92Russell King 88768b65f7305e54b822b2483c60de7d7b017526a92Russell King /* The DMA buffer is now the FIFO the TTY subsystem can use */ 88868b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->port.fifosize = PL011_DMA_BUFFER_SIZE; 889ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij uap->using_tx_dma = true; 890ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 891ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (!uap->dmarx.chan) 892ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij goto skip_rx; 893ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 894ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* Allocate and map DMA RX buffers */ 895ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij ret = pl011_sgbuf_init(uap->dmarx.chan, &uap->dmarx.sgbuf_a, 896ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij DMA_FROM_DEVICE); 897ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (ret) { 898ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dev_err(uap->port.dev, "failed to init DMA %s: %d\n", 899ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij "RX buffer A", ret); 900ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij goto skip_rx; 901ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij } 90268b65f7305e54b822b2483c60de7d7b017526a92Russell King 903ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij ret = pl011_sgbuf_init(uap->dmarx.chan, &uap->dmarx.sgbuf_b, 904ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij DMA_FROM_DEVICE); 905ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (ret) { 906ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dev_err(uap->port.dev, "failed to init DMA %s: %d\n", 907ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij "RX buffer B", ret); 908ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_a, 909ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij DMA_FROM_DEVICE); 910ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij goto skip_rx; 911ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij } 912ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 913ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij uap->using_rx_dma = true; 91468b65f7305e54b822b2483c60de7d7b017526a92Russell King 915ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijskip_rx: 91668b65f7305e54b822b2483c60de7d7b017526a92Russell King /* Turn on DMA error (RX/TX will be enabled on demand) */ 91768b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->dmacr |= UART011_DMAONERR; 91868b65f7305e54b822b2483c60de7d7b017526a92Russell King writew(uap->dmacr, uap->port.membase + UART011_DMACR); 91938d624361b2a82d6317c379aebf81b1b28210bb0Russell King 92038d624361b2a82d6317c379aebf81b1b28210bb0Russell King /* 92138d624361b2a82d6317c379aebf81b1b28210bb0Russell King * ST Micro variants has some specific dma burst threshold 92238d624361b2a82d6317c379aebf81b1b28210bb0Russell King * compensation. Set this to 16 bytes, so burst will only 92338d624361b2a82d6317c379aebf81b1b28210bb0Russell King * be issued above/below 16 bytes. 92438d624361b2a82d6317c379aebf81b1b28210bb0Russell King */ 92538d624361b2a82d6317c379aebf81b1b28210bb0Russell King if (uap->vendor->dma_threshold) 92638d624361b2a82d6317c379aebf81b1b28210bb0Russell King writew(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16, 92738d624361b2a82d6317c379aebf81b1b28210bb0Russell King uap->port.membase + ST_UART011_DMAWM); 928ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 929ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (uap->using_rx_dma) { 930ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (pl011_dma_rx_trigger_dma(uap)) 931ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dev_dbg(uap->port.dev, "could not trigger initial " 932ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij "RX DMA job, fall back to interrupt mode\n"); 933ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij } 93468b65f7305e54b822b2483c60de7d7b017526a92Russell King} 93568b65f7305e54b822b2483c60de7d7b017526a92Russell King 93668b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic void pl011_dma_shutdown(struct uart_amba_port *uap) 93768b65f7305e54b822b2483c60de7d7b017526a92Russell King{ 938ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (!(uap->using_tx_dma || uap->using_rx_dma)) 93968b65f7305e54b822b2483c60de7d7b017526a92Russell King return; 94068b65f7305e54b822b2483c60de7d7b017526a92Russell King 94168b65f7305e54b822b2483c60de7d7b017526a92Russell King /* Disable RX and TX DMA */ 94268b65f7305e54b822b2483c60de7d7b017526a92Russell King while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) 94368b65f7305e54b822b2483c60de7d7b017526a92Russell King barrier(); 94468b65f7305e54b822b2483c60de7d7b017526a92Russell King 94568b65f7305e54b822b2483c60de7d7b017526a92Russell King spin_lock_irq(&uap->port.lock); 94668b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE); 94768b65f7305e54b822b2483c60de7d7b017526a92Russell King writew(uap->dmacr, uap->port.membase + UART011_DMACR); 94868b65f7305e54b822b2483c60de7d7b017526a92Russell King spin_unlock_irq(&uap->port.lock); 94968b65f7305e54b822b2483c60de7d7b017526a92Russell King 950ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (uap->using_tx_dma) { 951ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* In theory, this should already be done by pl011_dma_flush_buffer */ 952ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dmaengine_terminate_all(uap->dmatx.chan); 953ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (uap->dmatx.queued) { 954ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1, 955ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij DMA_TO_DEVICE); 956ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij uap->dmatx.queued = false; 957ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij } 958ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 959ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij kfree(uap->dmatx.buf); 960ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij uap->using_tx_dma = false; 96168b65f7305e54b822b2483c60de7d7b017526a92Russell King } 96268b65f7305e54b822b2483c60de7d7b017526a92Russell King 963ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (uap->using_rx_dma) { 964ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dmaengine_terminate_all(uap->dmarx.chan); 965ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* Clean up the RX DMA */ 966ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_a, DMA_FROM_DEVICE); 967ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_b, DMA_FROM_DEVICE); 968ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij uap->using_rx_dma = false; 969ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij } 970ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij} 97168b65f7305e54b822b2483c60de7d7b017526a92Russell King 972ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic inline bool pl011_dma_rx_available(struct uart_amba_port *uap) 973ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{ 974ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij return uap->using_rx_dma; 97568b65f7305e54b822b2483c60de7d7b017526a92Russell King} 97668b65f7305e54b822b2483c60de7d7b017526a92Russell King 977ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic inline bool pl011_dma_rx_running(struct uart_amba_port *uap) 978ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{ 979ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij return uap->using_rx_dma && uap->dmarx.running; 980ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij} 981ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 982ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 98368b65f7305e54b822b2483c60de7d7b017526a92Russell King#else 98468b65f7305e54b822b2483c60de7d7b017526a92Russell King/* Blank functions if the DMA engine is not available */ 98568b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic inline void pl011_dma_probe(struct uart_amba_port *uap) 98668b65f7305e54b822b2483c60de7d7b017526a92Russell King{ 98768b65f7305e54b822b2483c60de7d7b017526a92Russell King} 98868b65f7305e54b822b2483c60de7d7b017526a92Russell King 98968b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic inline void pl011_dma_remove(struct uart_amba_port *uap) 99068b65f7305e54b822b2483c60de7d7b017526a92Russell King{ 99168b65f7305e54b822b2483c60de7d7b017526a92Russell King} 99268b65f7305e54b822b2483c60de7d7b017526a92Russell King 99368b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic inline void pl011_dma_startup(struct uart_amba_port *uap) 99468b65f7305e54b822b2483c60de7d7b017526a92Russell King{ 99568b65f7305e54b822b2483c60de7d7b017526a92Russell King} 99668b65f7305e54b822b2483c60de7d7b017526a92Russell King 99768b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic inline void pl011_dma_shutdown(struct uart_amba_port *uap) 99868b65f7305e54b822b2483c60de7d7b017526a92Russell King{ 99968b65f7305e54b822b2483c60de7d7b017526a92Russell King} 100068b65f7305e54b822b2483c60de7d7b017526a92Russell King 100168b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic inline bool pl011_dma_tx_irq(struct uart_amba_port *uap) 100268b65f7305e54b822b2483c60de7d7b017526a92Russell King{ 100368b65f7305e54b822b2483c60de7d7b017526a92Russell King return false; 100468b65f7305e54b822b2483c60de7d7b017526a92Russell King} 100568b65f7305e54b822b2483c60de7d7b017526a92Russell King 100668b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic inline void pl011_dma_tx_stop(struct uart_amba_port *uap) 100768b65f7305e54b822b2483c60de7d7b017526a92Russell King{ 100868b65f7305e54b822b2483c60de7d7b017526a92Russell King} 100968b65f7305e54b822b2483c60de7d7b017526a92Russell King 101068b65f7305e54b822b2483c60de7d7b017526a92Russell Kingstatic inline bool pl011_dma_tx_start(struct uart_amba_port *uap) 101168b65f7305e54b822b2483c60de7d7b017526a92Russell King{ 101268b65f7305e54b822b2483c60de7d7b017526a92Russell King return false; 101368b65f7305e54b822b2483c60de7d7b017526a92Russell King} 101468b65f7305e54b822b2483c60de7d7b017526a92Russell King 1015ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic inline void pl011_dma_rx_irq(struct uart_amba_port *uap) 1016ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{ 1017ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij} 1018ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 1019ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic inline void pl011_dma_rx_stop(struct uart_amba_port *uap) 1020ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{ 1021ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij} 1022ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 1023ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic inline int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap) 1024ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{ 1025ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij return -EIO; 1026ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij} 1027ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 1028ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic inline bool pl011_dma_rx_available(struct uart_amba_port *uap) 1029ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{ 1030ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij return false; 1031ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij} 1032ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 1033ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleijstatic inline bool pl011_dma_rx_running(struct uart_amba_port *uap) 1034ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij{ 1035ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij return false; 1036ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij} 1037ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 103868b65f7305e54b822b2483c60de7d7b017526a92Russell King#define pl011_dma_flush_buffer NULL 103968b65f7305e54b822b2483c60de7d7b017526a92Russell King#endif 104068b65f7305e54b822b2483c60de7d7b017526a92Russell King 104168b65f7305e54b822b2483c60de7d7b017526a92Russell King 1042c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu/* 1043c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu * pl011_lockup_wa 1044c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu * This workaround aims to break the deadlock situation 1045c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu * when after long transfer over uart in hardware flow 1046c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu * control, uart interrupt registers cannot be cleared. 1047c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu * Hence uart transfer gets blocked. 1048c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu * 1049c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu * It is seen that during such deadlock condition ICR 1050c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu * don't get cleared even on multiple write. This leads 1051c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu * pass_counter to decrease and finally reach zero. This 1052c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu * can be taken as trigger point to run this UART_BT_WA. 1053c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu * 1054c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu */ 1055c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahustatic void pl011_lockup_wa(unsigned long data) 1056c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu{ 1057c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu struct uart_amba_port *uap = amba_ports[0]; 1058c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu void __iomem *base = uap->port.membase; 1059c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu struct circ_buf *xmit = &uap->port.state->xmit; 1060c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu struct tty_struct *tty = uap->port.state->port.tty; 1061c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu int buf_empty_retries = 200; 1062c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu int loop; 1063c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu 1064c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu /* Stop HCI layer from submitting data for tx */ 1065c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu tty->hw_stopped = 1; 1066c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu while (!uart_circ_empty(xmit)) { 1067c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu if (buf_empty_retries-- == 0) 1068c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu break; 1069c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu udelay(100); 1070c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu } 1071c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu 1072c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu /* Backup registers */ 1073c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu for (loop = 0; loop < UART_WA_SAVE_NR; loop++) 1074c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu uart_wa_regdata[loop] = readl(base + uart_wa_reg[loop]); 1075c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu 1076c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu /* Disable UART so that FIFO data is flushed out */ 1077c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu writew(0x00, uap->port.membase + UART011_CR); 1078c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu 1079c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu /* Soft reset UART module */ 1080c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu if (uap->port.dev->platform_data) { 1081c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu struct amba_pl011_data *plat; 1082c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu 1083c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu plat = uap->port.dev->platform_data; 1084c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu if (plat->reset) 1085c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu plat->reset(); 1086c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu } 1087c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu 1088c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu /* Restore registers */ 1089c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu for (loop = 0; loop < UART_WA_SAVE_NR; loop++) 1090c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu writew(uart_wa_regdata[loop] , 1091c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu uap->port.membase + uart_wa_reg[loop]); 1092c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu 1093c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu /* Initialise the old status of the modem signals */ 1094c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu uap->old_status = readw(uap->port.membase + UART01x_FR) & 1095c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu UART01x_FR_MODEM_ANY; 1096c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu 1097c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu if (readl(base + UART011_MIS) & 0x2) 1098c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu printk(KERN_EMERG "UART_BT_WA: ***FAILED***\n"); 1099c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu 1100c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu /* Start Tx/Rx */ 1101c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu tty->hw_stopped = 0; 1102c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu} 1103c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu 1104b129a8ccd53f74c43e4c83c8e0031a4990040830Russell Kingstatic void pl011_stop_tx(struct uart_port *port) 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_amba_port *uap = (struct uart_amba_port *)port; 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uap->im &= ~UART011_TXIM; 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writew(uap->im, uap->port.membase + UART011_IMSC); 111068b65f7305e54b822b2483c60de7d7b017526a92Russell King pl011_dma_tx_stop(uap); 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1113b129a8ccd53f74c43e4c83c8e0031a4990040830Russell Kingstatic void pl011_start_tx(struct uart_port *port) 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_amba_port *uap = (struct uart_amba_port *)port; 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 111768b65f7305e54b822b2483c60de7d7b017526a92Russell King if (!pl011_dma_tx_start(uap)) { 111868b65f7305e54b822b2483c60de7d7b017526a92Russell King uap->im |= UART011_TXIM; 111968b65f7305e54b822b2483c60de7d7b017526a92Russell King writew(uap->im, uap->port.membase + UART011_IMSC); 112068b65f7305e54b822b2483c60de7d7b017526a92Russell King } 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl011_stop_rx(struct uart_port *port) 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_amba_port *uap = (struct uart_amba_port *)port; 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM| 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds UART011_PEIM|UART011_BEIM|UART011_OEIM); 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writew(uap->im, uap->port.membase + UART011_IMSC); 1130ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij 1131ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij pl011_dma_rx_stop(uap); 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl011_enable_ms(struct uart_port *port) 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_amba_port *uap = (struct uart_amba_port *)port; 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM; 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writew(uap->im, uap->port.membase + UART011_IMSC); 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11427d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl011_rx_chars(struct uart_amba_port *uap) 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1144ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox struct tty_struct *tty = uap->port.state->port.tty; 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 114629772c4e28cbb33ea1f8c6dcd130ebf190b91d85Linus Walleij pl011_fifo_to_tty(uap); 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11482389b272168ceec056ca1d8a870a97fa9c26e11aThomas Gleixner spin_unlock(&uap->port.lock); 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_flip_buffer_push(tty); 1150ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij /* 1151ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * If we were temporarily out of DMA mode for a while, 1152ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * attempt to switch back to DMA mode again. 1153ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij */ 1154ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (pl011_dma_rx_available(uap)) { 1155ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (pl011_dma_rx_trigger_dma(uap)) { 1156ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij dev_dbg(uap->port.dev, "could not trigger RX DMA job " 1157ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij "fall back to interrupt mode again\n"); 1158ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij uap->im |= UART011_RXIM; 1159ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij } else 1160ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij uap->im &= ~UART011_RXIM; 1161ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij writew(uap->im, uap->port.membase + UART011_IMSC); 1162ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij } 11632389b272168ceec056ca1d8a870a97fa9c26e11aThomas Gleixner spin_lock(&uap->port.lock); 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl011_tx_chars(struct uart_amba_port *uap) 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1168ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox struct circ_buf *xmit = &uap->port.state->xmit; 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int count; 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (uap->port.x_char) { 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writew(uap->port.x_char, uap->port.membase + UART01x_DR); 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uap->port.icount.tx++; 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uap->port.x_char = 0; 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) { 1178b129a8ccd53f74c43e4c83c8e0031a4990040830Russell King pl011_stop_tx(&uap->port); 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 118268b65f7305e54b822b2483c60de7d7b017526a92Russell King /* If we are using DMA mode, try to send some characters. */ 118368b65f7305e54b822b2483c60de7d7b017526a92Russell King if (pl011_dma_tx_irq(uap)) 118468b65f7305e54b822b2483c60de7d7b017526a92Russell King return; 118568b65f7305e54b822b2483c60de7d7b017526a92Russell King 1186ffca2b114c6a804d1307781df687e877a373a1c2Russell King count = uap->fifosize >> 1; 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR); 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); 11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uap->port.icount.tx++; 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (uart_circ_empty(xmit)) 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (--count > 0); 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_write_wakeup(&uap->port); 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (uart_circ_empty(xmit)) 1199b129a8ccd53f74c43e4c83c8e0031a4990040830Russell King pl011_stop_tx(&uap->port); 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl011_modem_status(struct uart_amba_port *uap) 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status, delta; 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY; 12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds delta = status ^ uap->old_status; 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uap->old_status = status; 12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!delta) 12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (delta & UART01x_FR_DCD) 12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD); 12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (delta & UART01x_FR_DSR) 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uap->port.icount.dsr++; 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (delta & UART01x_FR_CTS) 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS); 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1223bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox wake_up_interruptible(&uap->port.state->port.delta_msr_wait); 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12267d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t pl011_int(int irq, void *dev_id) 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_amba_port *uap = dev_id; 1229963cc981af620c7c07b5f6d1ab998b639e90ecb1Russell King unsigned long flags; 12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int handled = 0; 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1233963cc981af620c7c07b5f6d1ab998b639e90ecb1Russell King spin_lock_irqsave(&uap->port.lock, flags); 12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = readw(uap->port.membase + UART011_MIS); 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status) { 12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writew(status & ~(UART011_TXIS|UART011_RTIS| 12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds UART011_RXIS), 12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uap->port.membase + UART011_ICR); 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1242ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (status & (UART011_RTIS|UART011_RXIS)) { 1243ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (pl011_dma_rx_running(uap)) 1244ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij pl011_dma_rx_irq(uap); 1245ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij else 1246ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij pl011_rx_chars(uap); 1247ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij } 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & (UART011_DSRMIS|UART011_DCDMIS| 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds UART011_CTSMIS|UART011_RIMIS)) 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pl011_modem_status(uap); 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & UART011_TXIS) 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pl011_tx_chars(uap); 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1254c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu if (pass_counter-- == 0) { 1255c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu if (uap->interrupt_may_hang) 1256c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu tasklet_schedule(&pl011_lockup_tlet); 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1258c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu } 12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = readw(uap->port.membase + UART011_MIS); 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (status != 0); 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handled = 1; 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1265963cc981af620c7c07b5f6d1ab998b639e90ecb1Russell King spin_unlock_irqrestore(&uap->port.lock, flags); 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_RETVAL(handled); 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int pl01x_tx_empty(struct uart_port *port) 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_amba_port *uap = (struct uart_amba_port *)port; 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status = readw(uap->port.membase + UART01x_FR); 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT; 12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int pl01x_get_mctrl(struct uart_port *port) 12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_amba_port *uap = (struct uart_amba_port *)port; 12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int result = 0; 12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status = readw(uap->port.membase + UART01x_FR); 12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12835159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby#define TIOCMBIT(uartbit, tiocmbit) \ 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & uartbit) \ 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result |= tiocmbit 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12875159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR); 12885159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby TIOCMBIT(UART01x_FR_DSR, TIOCM_DSR); 12895159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby TIOCMBIT(UART01x_FR_CTS, TIOCM_CTS); 12905159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby TIOCMBIT(UART011_FR_RI, TIOCM_RNG); 12915159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby#undef TIOCMBIT 12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl) 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_amba_port *uap = (struct uart_amba_port *)port; 12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cr; 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cr = readw(uap->port.membase + UART011_CR); 13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13025159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby#define TIOCMBIT(tiocmbit, uartbit) \ 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mctrl & tiocmbit) \ 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cr |= uartbit; \ 13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else \ 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cr &= ~uartbit 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13085159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby TIOCMBIT(TIOCM_RTS, UART011_CR_RTS); 13095159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby TIOCMBIT(TIOCM_DTR, UART011_CR_DTR); 13105159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby TIOCMBIT(TIOCM_OUT1, UART011_CR_OUT1); 13115159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby TIOCMBIT(TIOCM_OUT2, UART011_CR_OUT2); 13125159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby TIOCMBIT(TIOCM_LOOP, UART011_CR_LBE); 13133b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent 13143b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent if (uap->autorts) { 13153b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent /* We need to disable auto-RTS if we want to turn RTS off */ 13163b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent TIOCMBIT(TIOCM_RTS, UART011_CR_RTSEN); 13173b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent } 13185159f40742508e03aed4273a9b3ef06f4e71929fJiri Slaby#undef TIOCMBIT 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writew(cr, uap->port.membase + UART011_CR); 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl011_break_ctl(struct uart_port *port, int break_state) 13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_amba_port *uap = (struct uart_amba_port *)port; 13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int lcr_h; 13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&uap->port.lock, flags); 1330ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij lcr_h = readw(uap->port.membase + uap->lcrh_tx); 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (break_state == -1) 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lcr_h |= UART01x_LCRH_BRK; 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lcr_h &= ~UART01x_LCRH_BRK; 1335ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij writew(lcr_h, uap->port.membase + uap->lcrh_tx); 13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&uap->port.lock, flags); 13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 133984b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel#ifdef CONFIG_CONSOLE_POLL 134084b5ae15216aa3ea0314f395536ef9829af21e14Jason Wesselstatic int pl010_get_poll_char(struct uart_port *port) 134184b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel{ 134284b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel struct uart_amba_port *uap = (struct uart_amba_port *)port; 134384b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel unsigned int status; 134484b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel 1345f5316b4aea024da9266d740322a5481657f6ce59Jason Wessel status = readw(uap->port.membase + UART01x_FR); 1346f5316b4aea024da9266d740322a5481657f6ce59Jason Wessel if (status & UART01x_FR_RXFE) 1347f5316b4aea024da9266d740322a5481657f6ce59Jason Wessel return NO_POLL_CHAR; 134884b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel 134984b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel return readw(uap->port.membase + UART01x_DR); 135084b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel} 135184b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel 135284b5ae15216aa3ea0314f395536ef9829af21e14Jason Wesselstatic void pl010_put_poll_char(struct uart_port *port, 135384b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel unsigned char ch) 135484b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel{ 135584b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel struct uart_amba_port *uap = (struct uart_amba_port *)port; 135684b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel 135784b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) 135884b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel barrier(); 135984b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel 136084b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel writew(ch, uap->port.membase + UART01x_DR); 136184b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel} 136284b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel 136384b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel#endif /* CONFIG_CONSOLE_POLL */ 136484b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl011_startup(struct uart_port *port) 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_amba_port *uap = (struct uart_amba_port *)port; 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cr; 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13714b4851c65d926f46e208e4731409022d986a1355Russell King retval = clk_prepare(uap->clk); 13724b4851c65d926f46e208e4731409022d986a1355Russell King if (retval) 13734b4851c65d926f46e208e4731409022d986a1355Russell King goto out; 13744b4851c65d926f46e208e4731409022d986a1355Russell King 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Try to enable the clock producer. 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = clk_enable(uap->clk); 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 13804b4851c65d926f46e208e4731409022d986a1355Russell King goto clk_unprep; 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uap->port.uartclk = clk_get_rate(uap->clk); 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate the IRQ 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap); 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto clk_dis; 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS); 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Provoke TX FIFO interrupt into asserting. 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE; 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writew(cr, uap->port.membase + UART011_CR); 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writew(0, uap->port.membase + UART011_FBRD); 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writew(1, uap->port.membase + UART011_IBRD); 1400ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij writew(0, uap->port.membase + uap->lcrh_rx); 1401ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij if (uap->lcrh_tx != uap->lcrh_rx) { 1402ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij int i; 1403ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij /* 1404ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij * Wait 10 PCLKs before writing LCRH_TX register, 1405ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij * to get this delay write read only register 10 times 1406ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij */ 1407ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij for (i = 0; i < 10; ++i) 1408ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij writew(0xff, uap->port.membase + UART011_MIS); 1409ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij writew(0, uap->port.membase + uap->lcrh_tx); 1410ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij } 14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writew(0, uap->port.membase + UART01x_DR); 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds barrier(); 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1415d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu /* restore RTS and DTR */ 1416d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR); 1417d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writew(cr, uap->port.membase + UART011_CR); 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14205063e2c567ee569cccfc01ebf80c898cb4e6833aRussell King /* Clear pending error interrupts */ 14215063e2c567ee569cccfc01ebf80c898cb4e6833aRussell King writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS, 14225063e2c567ee569cccfc01ebf80c898cb4e6833aRussell King uap->port.membase + UART011_ICR); 14235063e2c567ee569cccfc01ebf80c898cb4e6833aRussell King 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * initialise the old status of the modem signals 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uap->old_status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY; 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 142968b65f7305e54b822b2483c60de7d7b017526a92Russell King /* Startup DMA */ 143068b65f7305e54b822b2483c60de7d7b017526a92Russell King pl011_dma_startup(uap); 143168b65f7305e54b822b2483c60de7d7b017526a92Russell King 14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1433ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * Finally, enable interrupts, only timeouts when using DMA 1434ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * if initial RX DMA job failed, start in interrupt mode 1435ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij * as well. 14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&uap->port.lock); 1438ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij uap->im = UART011_RTIM; 1439ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij if (!pl011_dma_rx_running(uap)) 1440ead76f329f777c7301e0a5456a0a1c7a081570bdLinus Walleij uap->im |= UART011_RXIM; 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writew(uap->im, uap->port.membase + UART011_IMSC); 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&uap->port.lock); 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1444c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu if (uap->port.dev->platform_data) { 1445c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu struct amba_pl011_data *plat; 1446c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu 1447c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu plat = uap->port.dev->platform_data; 1448c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu if (plat->init) 1449c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu plat->init(); 1450c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu } 1451c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_dis: 14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_disable(uap->clk); 14564b4851c65d926f46e208e4731409022d986a1355Russell King clk_unprep: 14574b4851c65d926f46e208e4731409022d986a1355Russell King clk_unprepare(uap->clk); 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1462ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleijstatic void pl011_shutdown_channel(struct uart_amba_port *uap, 1463ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij unsigned int lcrh) 1464ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij{ 1465ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij unsigned long val; 1466ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij 1467ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij val = readw(uap->port.membase + lcrh); 1468ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN); 1469ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij writew(val, uap->port.membase + lcrh); 1470ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij} 1471ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij 14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl011_shutdown(struct uart_port *port) 14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_amba_port *uap = (struct uart_amba_port *)port; 1475d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu unsigned int cr; 14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * disable all interrupts 14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&uap->port.lock); 14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uap->im = 0; 14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writew(uap->im, uap->port.membase + UART011_IMSC); 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writew(0xffff, uap->port.membase + UART011_ICR); 14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&uap->port.lock); 14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 148668b65f7305e54b822b2483c60de7d7b017526a92Russell King pl011_dma_shutdown(uap); 148768b65f7305e54b822b2483c60de7d7b017526a92Russell King 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free the interrupt 14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(uap->port.irq, uap); 14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * disable the port 1495d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu * disable the port. It should not disable RTS and DTR. 1496d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu * Also RTS and DTR state should be preserved to restore 1497d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu * it during startup(). 14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14993b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent uap->autorts = false; 1500d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu cr = readw(uap->port.membase + UART011_CR); 1501d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu uap->old_cr = cr; 1502d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu cr &= UART011_CR_RTS | UART011_CR_DTR; 1503d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu cr |= UART01x_CR_UARTEN | UART011_CR_TXE; 1504d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu writew(cr, uap->port.membase + UART011_CR); 15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * disable break condition and fifos 15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1509ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij pl011_shutdown_channel(uap, uap->lcrh_rx); 1510ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij if (uap->lcrh_rx != uap->lcrh_tx) 1511ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij pl011_shutdown_channel(uap, uap->lcrh_tx); 15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Shut down the clock producer 15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_disable(uap->clk); 15174b4851c65d926f46e208e4731409022d986a1355Russell King clk_unprepare(uap->clk); 1518c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu 1519c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu if (uap->port.dev->platform_data) { 1520c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu struct amba_pl011_data *plat; 1521c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu 1522c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu plat = uap->port.dev->platform_data; 1523c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu if (plat->exit) 1524c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu plat->exit(); 1525c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu } 1526c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu 15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 1530606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Coxpl011_set_termios(struct uart_port *port, struct ktermios *termios, 1531606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox struct ktermios *old) 15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15333b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent struct uart_amba_port *uap = (struct uart_amba_port *)port; 15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int lcr_h, old_cr; 15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1536c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King unsigned int baud, quot, clkdiv; 1537c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King 1538c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King if (uap->vendor->oversampling) 1539c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King clkdiv = 8; 1540c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King else 1541c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King clkdiv = 16; 15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ask the core to calculate the divisor for us. 15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1546ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij baud = uart_get_baud_rate(port, termios, old, 0, 1547c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King port->uartclk / clkdiv); 1548ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij 1549ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij if (baud > port->uartclk/16) 1550ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud); 1551ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij else 1552ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud); 15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (termios->c_cflag & CSIZE) { 15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS5: 15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lcr_h = UART01x_LCRH_WLEN_5; 15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS6: 15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lcr_h = UART01x_LCRH_WLEN_6; 15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS7: 15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lcr_h = UART01x_LCRH_WLEN_7; 15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: // CS8 15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lcr_h = UART01x_LCRH_WLEN_8; 15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (termios->c_cflag & CSTOPB) 15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lcr_h |= UART01x_LCRH_STP2; 15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (termios->c_cflag & PARENB) { 15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lcr_h |= UART01x_LCRH_PEN; 15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(termios->c_cflag & PARODD)) 15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lcr_h |= UART01x_LCRH_EPS; 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1575ffca2b114c6a804d1307781df687e877a373a1c2Russell King if (uap->fifosize > 1) 15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lcr_h |= UART01x_LCRH_FEN; 15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port->lock, flags); 15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Update the per-port timeout. 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_update_timeout(port, termios->c_cflag, baud); 15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1585b63d4f0fb80918ab37b6c0ee1adcd49e05c9994cRussell King port->read_status_mask = UART011_DR_OE | 255; 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (termios->c_iflag & INPCK) 1587b63d4f0fb80918ab37b6c0ee1adcd49e05c9994cRussell King port->read_status_mask |= UART011_DR_FE | UART011_DR_PE; 15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (termios->c_iflag & (BRKINT | PARMRK)) 1589b63d4f0fb80918ab37b6c0ee1adcd49e05c9994cRussell King port->read_status_mask |= UART011_DR_BE; 15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Characters to ignore 15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->ignore_status_mask = 0; 15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (termios->c_iflag & IGNPAR) 1596b63d4f0fb80918ab37b6c0ee1adcd49e05c9994cRussell King port->ignore_status_mask |= UART011_DR_FE | UART011_DR_PE; 15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (termios->c_iflag & IGNBRK) { 1598b63d4f0fb80918ab37b6c0ee1adcd49e05c9994cRussell King port->ignore_status_mask |= UART011_DR_BE; 15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we're ignoring parity and break indicators, 16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ignore overruns too (for real raw support). 16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (termios->c_iflag & IGNPAR) 1604b63d4f0fb80918ab37b6c0ee1adcd49e05c9994cRussell King port->ignore_status_mask |= UART011_DR_OE; 16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ignore all characters if CREAD is not set. 16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((termios->c_cflag & CREAD) == 0) 1611b63d4f0fb80918ab37b6c0ee1adcd49e05c9994cRussell King port->ignore_status_mask |= UART_DUMMY_DR_RX; 16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (UART_ENABLE_MS(port, termios->c_cflag)) 16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pl011_enable_ms(port); 16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* first, disable everything */ 16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds old_cr = readw(port->membase + UART011_CR); 16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writew(0, port->membase + UART011_CR); 16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16203b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent if (termios->c_cflag & CRTSCTS) { 16213b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent if (old_cr & UART011_CR_RTS) 16223b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent old_cr |= UART011_CR_RTSEN; 16233b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent 16243b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent old_cr |= UART011_CR_CTSEN; 16253b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent uap->autorts = true; 16263b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent } else { 16273b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent old_cr &= ~(UART011_CR_CTSEN | UART011_CR_RTSEN); 16283b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent uap->autorts = false; 16293b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent } 16303b43816f685fc6c2531f43514662f796f4601ffcRabin Vincent 1631c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King if (uap->vendor->oversampling) { 1632c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King if (baud > port->uartclk / 16) 1633ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij old_cr |= ST_UART011_CR_OVSFACT; 1634ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij else 1635ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij old_cr &= ~ST_UART011_CR_OVSFACT; 1636ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij } 1637ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij 16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set baud rate */ 16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writew(quot & 0x3f, port->membase + UART011_FBRD); 16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writew(quot >> 6, port->membase + UART011_IBRD); 16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ----------v----------v----------v----------v----- 16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L 16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ----------^----------^----------^----------^----- 16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1647ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij writew(lcr_h, port->membase + uap->lcrh_rx); 1648ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij if (uap->lcrh_rx != uap->lcrh_tx) { 1649ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij int i; 1650ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij /* 1651ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij * Wait 10 PCLKs before writing LCRH_TX register, 1652ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij * to get this delay write read only register 10 times 1653ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij */ 1654ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij for (i = 0; i < 10; ++i) 1655ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij writew(0xff, uap->port.membase + UART011_MIS); 1656ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij writew(lcr_h, port->membase + uap->lcrh_tx); 1657ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij } 16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writew(old_cr, port->membase + UART011_CR); 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port->lock, flags); 16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *pl011_type(struct uart_port *port) 16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1665e8a7ba86ff993311f8712e5b3bb2e3892e82df5fRussell King struct uart_amba_port *uap = (struct uart_amba_port *)port; 1666e8a7ba86ff993311f8712e5b3bb2e3892e82df5fRussell King return uap->port.type == PORT_AMBA ? uap->type : NULL; 16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Release the memory region(s) being used by 'port' 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl010_release_port(struct uart_port *port) 16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_mem_region(port->mapbase, SZ_4K); 16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Request the memory region(s) being used by 'port' 16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl010_request_port(struct uart_port *port) 16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return request_mem_region(port->mapbase, SZ_4K, "uart-pl011") 16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds != NULL ? 0 : -EBUSY; 16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Configure/autoconfigure the port. 16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pl010_config_port(struct uart_port *port, int flags) 16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (flags & UART_CONFIG_TYPE) { 16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->type = PORT_AMBA; 16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pl010_request_port(port); 16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * verify the new serial_struct (for TIOCSSERIAL). 16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl010_verify_port(struct uart_port *port, struct serial_struct *ser) 17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA) 17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EINVAL; 1705a62c41337356989387d15020dc0f0288aaacfa44Yinghai Lu if (ser->irq < 0 || ser->irq >= nr_irqs) 17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EINVAL; 17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ser->baud_base < 9600) 17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EINVAL; 17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct uart_ops amba_pl011_pops = { 17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .tx_empty = pl01x_tx_empty, 17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_mctrl = pl011_set_mctrl, 17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_mctrl = pl01x_get_mctrl, 17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .stop_tx = pl011_stop_tx, 17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .start_tx = pl011_start_tx, 17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .stop_rx = pl011_stop_rx, 17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .enable_ms = pl011_enable_ms, 17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .break_ctl = pl011_break_ctl, 17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .startup = pl011_startup, 17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .shutdown = pl011_shutdown, 172368b65f7305e54b822b2483c60de7d7b017526a92Russell King .flush_buffer = pl011_dma_flush_buffer, 17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_termios = pl011_set_termios, 17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .type = pl011_type, 17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .release_port = pl010_release_port, 17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .request_port = pl010_request_port, 17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .config_port = pl010_config_port, 17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .verify_port = pl010_verify_port, 173084b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel#ifdef CONFIG_CONSOLE_POLL 173184b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel .poll_get_char = pl010_get_poll_char, 173284b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel .poll_put_char = pl010_put_poll_char, 173384b5ae15216aa3ea0314f395536ef9829af21e14Jason Wessel#endif 17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct uart_amba_port *amba_ports[UART_NR]; 17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE 17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1740d358788f3f30113e49882187d794832905e42592Russell Kingstatic void pl011_console_putchar(struct uart_port *port, int ch) 17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1742d358788f3f30113e49882187d794832905e42592Russell King struct uart_amba_port *uap = (struct uart_amba_port *)port; 17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1744d358788f3f30113e49882187d794832905e42592Russell King while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) 1745d358788f3f30113e49882187d794832905e42592Russell King barrier(); 17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writew(ch, uap->port.membase + UART01x_DR); 17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldspl011_console_write(struct console *co, const char *s, unsigned int count) 17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_amba_port *uap = amba_ports[co->index]; 17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status, old_cr, new_cr; 1754ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent unsigned long flags; 1755ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent int locked = 1; 17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_enable(uap->clk); 17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1759ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent local_irq_save(flags); 1760ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent if (uap->port.sysrq) 1761ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent locked = 0; 1762ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent else if (oops_in_progress) 1763ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent locked = spin_trylock(&uap->port.lock); 1764ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent else 1765ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent spin_lock(&uap->port.lock); 1766ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent 17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * First save the CR then disable the interrupts 17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds old_cr = readw(uap->port.membase + UART011_CR); 17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_cr = old_cr & ~UART011_CR_CTSEN; 17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE; 17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writew(new_cr, uap->port.membase + UART011_CR); 17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1775d358788f3f30113e49882187d794832905e42592Russell King uart_console_write(&uap->port, s, count, pl011_console_putchar); 17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Finally, wait for transmitter to become empty 17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and restore the TCR 17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = readw(uap->port.membase + UART01x_FR); 17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (status & UART01x_FR_BUSY); 17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writew(old_cr, uap->port.membase + UART011_CR); 17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1786ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent if (locked) 1787ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent spin_unlock(&uap->port.lock); 1788ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent local_irq_restore(flags); 1789ef605fdb33883d687cff5ba75095a91b313b4966Rabin Vincent 17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_disable(uap->clk); 17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __init 17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldspl011_console_get_options(struct uart_amba_port *uap, int *baud, 17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int *parity, int *bits) 17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) { 17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int lcr_h, ibrd, fbrd; 17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1800ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij lcr_h = readw(uap->port.membase + uap->lcrh_tx); 18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *parity = 'n'; 18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lcr_h & UART01x_LCRH_PEN) { 18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lcr_h & UART01x_LCRH_EPS) 18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *parity = 'e'; 18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *parity = 'o'; 18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7) 18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *bits = 7; 18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *bits = 8; 18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ibrd = readw(uap->port.membase + UART011_IBRD); 18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fbrd = readw(uap->port.membase + UART011_FBRD); 18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd); 1819ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij 1820c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King if (uap->vendor->oversampling) { 1821ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij if (readw(uap->port.membase + UART011_CR) 1822ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij & ST_UART011_CR_OVSFACT) 1823ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij *baud *= 2; 1824ac3e3fb424d44109dda3b1a3459e1b30fa60ac4aLinus Walleij } 18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init pl011_console_setup(struct console *co, char *options) 18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_amba_port *uap; 18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int baud = 38400; 18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bits = 8; 18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int parity = 'n'; 18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int flow = 'n'; 18354b4851c65d926f46e208e4731409022d986a1355Russell King int ret; 18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check whether an invalid uart number has been specified, and 18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if so, search for the first available port that does have 18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * console support. 18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (co->index >= UART_NR) 18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds co->index = 0; 18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uap = amba_ports[co->index]; 1845d28122a5877cc40350fa801353fd5a9350563ec3Russell King if (!uap) 1846d28122a5877cc40350fa801353fd5a9350563ec3Russell King return -ENODEV; 18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18484b4851c65d926f46e208e4731409022d986a1355Russell King ret = clk_prepare(uap->clk); 18494b4851c65d926f46e208e4731409022d986a1355Russell King if (ret) 18504b4851c65d926f46e208e4731409022d986a1355Russell King return ret; 18514b4851c65d926f46e208e4731409022d986a1355Russell King 1852c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu if (uap->port.dev->platform_data) { 1853c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu struct amba_pl011_data *plat; 1854c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu 1855c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu plat = uap->port.dev->platform_data; 1856c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu if (plat->init) 1857c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu plat->init(); 1858c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu } 1859c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu 18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uap->port.uartclk = clk_get_rate(uap->clk); 18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (options) 18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_parse_options(options, &baud, &parity, &bits, &flow); 18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pl011_console_get_options(uap, &baud, &parity, &bits); 18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return uart_set_options(&uap->port, co, baud, parity, bits, flow); 18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18702d93486c6c110cf81db720359b4ec20de9c91450Vincent Sandersstatic struct uart_driver amba_reg; 18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct console amba_console = { 18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "ttyAMA", 18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = pl011_console_write, 18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .device = uart_console_device, 18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .setup = pl011_console_setup, 18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .flags = CON_PRINTBUFFER, 18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .index = -1, 18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .data = &amba_reg, 18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AMBA_CONSOLE (&amba_console) 18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AMBA_CONSOLE NULL 18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct uart_driver amba_reg = { 18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_name = "ttyAMA", 18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .dev_name = "ttyAMA", 18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .major = SERIAL_AMBA_MAJOR, 18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .minor = SERIAL_AMBA_MINOR, 18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .nr = UART_NR, 18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cons = AMBA_CONSOLE, 18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1896aa25afad2ca60d19457849ea75e9c31236f4e174Russell Kingstatic int pl011_probe(struct amba_device *dev, const struct amba_id *id) 18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_amba_port *uap; 18995926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini struct vendor_data *vendor = id->data; 19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *base; 19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, ret; 19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(amba_ports); i++) 19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (amba_ports[i] == NULL) 19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i == ARRAY_SIZE(amba_ports)) { 19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EBUSY; 19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1912dd00cc486ab1c17049a535413d1751ef3482141cYoann Padioleau uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL); 19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (uap == NULL) { 19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENOMEM; 19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1918dc890c2dcd63a90de68ee5f0253eefbb89d725f0Linus Walleij base = ioremap(dev->res.start, resource_size(&dev->res)); 19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!base) { 19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENOMEM; 19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free; 19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1924ee569c43e340202fb0ba427c57b77568a32b9a3aRussell King uap->clk = clk_get(&dev->dev, NULL); 19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(uap->clk)) { 19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = PTR_ERR(uap->clk); 19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto unmap; 19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1930c19f12b5ef3adf3c139eabbe3d3d0201838b77b1Russell King uap->vendor = vendor; 1931ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij uap->lcrh_rx = vendor->lcrh_rx; 1932ec489aa8f993f8d2ec962ce113071faac482aa27Linus Walleij uap->lcrh_tx = vendor->lcrh_tx; 1933d8d8ffa477831b713ddfa2ad4d0ca545f3b567e5Shreshtha Kumar Sahu uap->old_cr = 0; 1934ffca2b114c6a804d1307781df687e877a373a1c2Russell King uap->fifosize = vendor->fifosize; 1935c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3Shreshtha Kumar Sahu uap->interrupt_may_hang = vendor->interrupt_may_hang; 19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uap->port.dev = &dev->dev; 19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uap->port.mapbase = dev->res.start; 19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uap->port.membase = base; 19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uap->port.iotype = UPIO_MEM; 19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uap->port.irq = dev->irq[0]; 1941ffca2b114c6a804d1307781df687e877a373a1c2Russell King uap->port.fifosize = uap->fifosize; 19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uap->port.ops = &amba_pl011_pops; 19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uap->port.flags = UPF_BOOT_AUTOCONF; 19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uap->port.line = i; 194568b65f7305e54b822b2483c60de7d7b017526a92Russell King pl011_dma_probe(uap); 19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1947e8a7ba86ff993311f8712e5b3bb2e3892e82df5fRussell King snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev)); 1948e8a7ba86ff993311f8712e5b3bb2e3892e82df5fRussell King 19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amba_ports[i] = uap; 19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amba_set_drvdata(dev, uap); 19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = uart_add_one_port(&amba_reg, &uap->port); 19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) { 19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amba_set_drvdata(dev, NULL); 19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amba_ports[i] = NULL; 195668b65f7305e54b822b2483c60de7d7b017526a92Russell King pl011_dma_remove(uap); 19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_put(uap->clk); 19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unmap: 19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iounmap(base); 19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free: 19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(uap); 19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: 19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pl011_remove(struct amba_device *dev) 19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_amba_port *uap = amba_get_drvdata(dev); 19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amba_set_drvdata(dev, NULL); 19731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_remove_one_port(&amba_reg, &uap->port); 19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(amba_ports); i++) 19771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (amba_ports[i] == uap) 19781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amba_ports[i] = NULL; 19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 198068b65f7305e54b822b2483c60de7d7b017526a92Russell King pl011_dma_remove(uap); 19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iounmap(uap->port.membase); 19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_put(uap->clk); 19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(uap); 19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 19851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1987b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen#ifdef CONFIG_PM 1988b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chenstatic int pl011_suspend(struct amba_device *dev, pm_message_t state) 1989b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen{ 1990b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen struct uart_amba_port *uap = amba_get_drvdata(dev); 1991b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen 1992b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen if (!uap) 1993b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen return -EINVAL; 1994b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen 1995b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen return uart_suspend_port(&amba_reg, &uap->port); 1996b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen} 1997b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen 1998b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chenstatic int pl011_resume(struct amba_device *dev) 1999b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen{ 2000b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen struct uart_amba_port *uap = amba_get_drvdata(dev); 2001b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen 2002b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen if (!uap) 2003b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen return -EINVAL; 2004b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen 2005b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen return uart_resume_port(&amba_reg, &uap->port); 2006b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen} 2007b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen#endif 2008b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen 20092c39c9e149f45ec15a6985cb06ec8f6d904bb35eRussell Kingstatic struct amba_id pl011_ids[] = { 20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id = 0x00041011, 20121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .mask = 0x000fffff, 20135926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini .data = &vendor_arm, 20145926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini }, 20155926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini { 20165926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini .id = 0x00380802, 20175926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini .mask = 0x00ffffff, 20185926a295bb78272b3f648f62febecd19a1b6a6caAlessandro Rubini .data = &vendor_st, 20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 0, 0 }, 20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 202360f7a33b826148fd96cfa8a9e10b84ef444e78feDave MartinMODULE_DEVICE_TABLE(amba, pl011_ids); 202460f7a33b826148fd96cfa8a9e10b84ef444e78feDave Martin 20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct amba_driver pl011_driver = { 20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .drv = { 20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "uart-pl011", 20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = pl011_ids, 20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = pl011_probe, 20311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .remove = pl011_remove, 2032b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen#ifdef CONFIG_PM 2033b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen .suspend = pl011_suspend, 2034b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen .resume = pl011_resume, 2035b736b89f8a001cb73f020ca90a6fac77861cddf6Leo Chen#endif 20361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init pl011_init(void) 20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 20411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "Serial: AMBA PL011 UART driver\n"); 20421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = uart_register_driver(&amba_reg); 20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret == 0) { 20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = amba_driver_register(&pl011_driver); 20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_unregister_driver(&amba_reg); 20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit pl011_exit(void) 20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amba_driver_unregister(&pl011_driver); 20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_unregister_driver(&amba_reg); 20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20584dd9e742df98f8f600b4302d3adbb087a68237f7Alessandro Rubini/* 20594dd9e742df98f8f600b4302d3adbb087a68237f7Alessandro Rubini * While this can be a module, if builtin it's most likely the console 20604dd9e742df98f8f600b4302d3adbb087a68237f7Alessandro Rubini * So let's leave module_exit but move module_init to an earlier place 20614dd9e742df98f8f600b4302d3adbb087a68237f7Alessandro Rubini */ 20624dd9e742df98f8f600b4302d3adbb087a68237f7Alessandro Rubiniarch_initcall(pl011_init); 20631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(pl011_exit); 20641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd"); 20661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("ARM AMBA serial port driver"); 20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 2068