162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Freescale QUICC Engine UART device driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author: Timur Tabi <timur@freescale.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright 2007 Freescale Semiconductor, Inc. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * This driver adds support for UART devices via Freescale's QUICC Engine 1062306a36Sopenharmony_ci * found on some Freescale SOCs. 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * If Soft-UART support is needed but not already present, then this driver 1362306a36Sopenharmony_ci * will request and upload the "Soft-UART" microcode upon probe. The 1462306a36Sopenharmony_ci * filename of the microcode should be fsl_qe_ucode_uart_X_YZ.bin, where "X" 1562306a36Sopenharmony_ci * is the name of the SOC (e.g. 8323), and YZ is the revision of the SOC, 1662306a36Sopenharmony_ci * (e.g. "11" for 1.1). 1762306a36Sopenharmony_ci */ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <linux/platform_device.h> 2162306a36Sopenharmony_ci#include <linux/serial.h> 2262306a36Sopenharmony_ci#include <linux/serial_core.h> 2362306a36Sopenharmony_ci#include <linux/slab.h> 2462306a36Sopenharmony_ci#include <linux/tty.h> 2562306a36Sopenharmony_ci#include <linux/tty_flip.h> 2662306a36Sopenharmony_ci#include <linux/io.h> 2762306a36Sopenharmony_ci#include <linux/of.h> 2862306a36Sopenharmony_ci#include <linux/of_address.h> 2962306a36Sopenharmony_ci#include <linux/of_irq.h> 3062306a36Sopenharmony_ci#include <linux/dma-mapping.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include <soc/fsl/qe/ucc_slow.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include <linux/firmware.h> 3562306a36Sopenharmony_ci#include <soc/fsl/cpm.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#ifdef CONFIG_PPC32 3862306a36Sopenharmony_ci#include <asm/reg.h> /* mfspr, SPRN_SVR */ 3962306a36Sopenharmony_ci#endif 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* 4262306a36Sopenharmony_ci * The GUMR flag for Soft UART. This would normally be defined in qe.h, 4362306a36Sopenharmony_ci * but Soft-UART is a hack and we want to keep everything related to it in 4462306a36Sopenharmony_ci * this file. 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_ci#define UCC_SLOW_GUMR_H_SUART 0x00004000 /* Soft-UART */ 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* 4962306a36Sopenharmony_ci * soft_uart is 1 if we need to use Soft-UART mode 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_cistatic int soft_uart; 5262306a36Sopenharmony_ci/* 5362306a36Sopenharmony_ci * firmware_loaded is 1 if the firmware has been loaded, 0 otherwise. 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_cistatic int firmware_loaded; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* Enable this macro to configure all serial ports in internal loopback 5862306a36Sopenharmony_ci mode */ 5962306a36Sopenharmony_ci/* #define LOOPBACK */ 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* The major and minor device numbers are defined in 6262306a36Sopenharmony_ci * Documentation/admin-guide/devices.txt. For the QE 6362306a36Sopenharmony_ci * UART, we have major number 204 and minor numbers 46 - 49, which are the 6462306a36Sopenharmony_ci * same as for the CPM2. This decision was made because no Freescale part 6562306a36Sopenharmony_ci * has both a CPM and a QE. 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_ci#define SERIAL_QE_MAJOR 204 6862306a36Sopenharmony_ci#define SERIAL_QE_MINOR 46 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* Since we only have minor numbers 46 - 49, there is a hard limit of 4 ports */ 7162306a36Sopenharmony_ci#define UCC_MAX_UART 4 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* The number of buffer descriptors for receiving characters. */ 7462306a36Sopenharmony_ci#define RX_NUM_FIFO 4 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* The number of buffer descriptors for transmitting characters. */ 7762306a36Sopenharmony_ci#define TX_NUM_FIFO 4 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/* The maximum size of the character buffer for a single RX BD. */ 8062306a36Sopenharmony_ci#define RX_BUF_SIZE 32 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* The maximum size of the character buffer for a single TX BD. */ 8362306a36Sopenharmony_ci#define TX_BUF_SIZE 32 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* 8662306a36Sopenharmony_ci * The number of jiffies to wait after receiving a close command before the 8762306a36Sopenharmony_ci * device is actually closed. This allows the last few characters to be 8862306a36Sopenharmony_ci * sent over the wire. 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci#define UCC_WAIT_CLOSING 100 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistruct ucc_uart_pram { 9362306a36Sopenharmony_ci struct ucc_slow_pram common; 9462306a36Sopenharmony_ci u8 res1[8]; /* reserved */ 9562306a36Sopenharmony_ci __be16 maxidl; /* Maximum idle chars */ 9662306a36Sopenharmony_ci __be16 idlc; /* temp idle counter */ 9762306a36Sopenharmony_ci __be16 brkcr; /* Break count register */ 9862306a36Sopenharmony_ci __be16 parec; /* receive parity error counter */ 9962306a36Sopenharmony_ci __be16 frmec; /* receive framing error counter */ 10062306a36Sopenharmony_ci __be16 nosec; /* receive noise counter */ 10162306a36Sopenharmony_ci __be16 brkec; /* receive break condition counter */ 10262306a36Sopenharmony_ci __be16 brkln; /* last received break length */ 10362306a36Sopenharmony_ci __be16 uaddr[2]; /* UART address character 1 & 2 */ 10462306a36Sopenharmony_ci __be16 rtemp; /* Temp storage */ 10562306a36Sopenharmony_ci __be16 toseq; /* Transmit out of sequence char */ 10662306a36Sopenharmony_ci __be16 cchars[8]; /* control characters 1-8 */ 10762306a36Sopenharmony_ci __be16 rccm; /* receive control character mask */ 10862306a36Sopenharmony_ci __be16 rccr; /* receive control character register */ 10962306a36Sopenharmony_ci __be16 rlbc; /* receive last break character */ 11062306a36Sopenharmony_ci __be16 res2; /* reserved */ 11162306a36Sopenharmony_ci __be32 res3; /* reserved, should be cleared */ 11262306a36Sopenharmony_ci u8 res4; /* reserved, should be cleared */ 11362306a36Sopenharmony_ci u8 res5[3]; /* reserved, should be cleared */ 11462306a36Sopenharmony_ci __be32 res6; /* reserved, should be cleared */ 11562306a36Sopenharmony_ci __be32 res7; /* reserved, should be cleared */ 11662306a36Sopenharmony_ci __be32 res8; /* reserved, should be cleared */ 11762306a36Sopenharmony_ci __be32 res9; /* reserved, should be cleared */ 11862306a36Sopenharmony_ci __be32 res10; /* reserved, should be cleared */ 11962306a36Sopenharmony_ci __be32 res11; /* reserved, should be cleared */ 12062306a36Sopenharmony_ci __be32 res12; /* reserved, should be cleared */ 12162306a36Sopenharmony_ci __be32 res13; /* reserved, should be cleared */ 12262306a36Sopenharmony_ci/* The rest is for Soft-UART only */ 12362306a36Sopenharmony_ci __be16 supsmr; /* 0x90, Shadow UPSMR */ 12462306a36Sopenharmony_ci __be16 res92; /* 0x92, reserved, initialize to 0 */ 12562306a36Sopenharmony_ci __be32 rx_state; /* 0x94, RX state, initialize to 0 */ 12662306a36Sopenharmony_ci __be32 rx_cnt; /* 0x98, RX count, initialize to 0 */ 12762306a36Sopenharmony_ci u8 rx_length; /* 0x9C, Char length, set to 1+CL+PEN+1+SL */ 12862306a36Sopenharmony_ci u8 rx_bitmark; /* 0x9D, reserved, initialize to 0 */ 12962306a36Sopenharmony_ci u8 rx_temp_dlst_qe; /* 0x9E, reserved, initialize to 0 */ 13062306a36Sopenharmony_ci u8 res14[0xBC - 0x9F]; /* reserved */ 13162306a36Sopenharmony_ci __be32 dump_ptr; /* 0xBC, Dump pointer */ 13262306a36Sopenharmony_ci __be32 rx_frame_rem; /* 0xC0, reserved, initialize to 0 */ 13362306a36Sopenharmony_ci u8 rx_frame_rem_size; /* 0xC4, reserved, initialize to 0 */ 13462306a36Sopenharmony_ci u8 tx_mode; /* 0xC5, mode, 0=AHDLC, 1=UART */ 13562306a36Sopenharmony_ci __be16 tx_state; /* 0xC6, TX state */ 13662306a36Sopenharmony_ci u8 res15[0xD0 - 0xC8]; /* reserved */ 13762306a36Sopenharmony_ci __be32 resD0; /* 0xD0, reserved, initialize to 0 */ 13862306a36Sopenharmony_ci u8 resD4; /* 0xD4, reserved, initialize to 0 */ 13962306a36Sopenharmony_ci __be16 resD5; /* 0xD5, reserved, initialize to 0 */ 14062306a36Sopenharmony_ci} __attribute__ ((packed)); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/* SUPSMR definitions, for Soft-UART only */ 14362306a36Sopenharmony_ci#define UCC_UART_SUPSMR_SL 0x8000 14462306a36Sopenharmony_ci#define UCC_UART_SUPSMR_RPM_MASK 0x6000 14562306a36Sopenharmony_ci#define UCC_UART_SUPSMR_RPM_ODD 0x0000 14662306a36Sopenharmony_ci#define UCC_UART_SUPSMR_RPM_LOW 0x2000 14762306a36Sopenharmony_ci#define UCC_UART_SUPSMR_RPM_EVEN 0x4000 14862306a36Sopenharmony_ci#define UCC_UART_SUPSMR_RPM_HIGH 0x6000 14962306a36Sopenharmony_ci#define UCC_UART_SUPSMR_PEN 0x1000 15062306a36Sopenharmony_ci#define UCC_UART_SUPSMR_TPM_MASK 0x0C00 15162306a36Sopenharmony_ci#define UCC_UART_SUPSMR_TPM_ODD 0x0000 15262306a36Sopenharmony_ci#define UCC_UART_SUPSMR_TPM_LOW 0x0400 15362306a36Sopenharmony_ci#define UCC_UART_SUPSMR_TPM_EVEN 0x0800 15462306a36Sopenharmony_ci#define UCC_UART_SUPSMR_TPM_HIGH 0x0C00 15562306a36Sopenharmony_ci#define UCC_UART_SUPSMR_FRZ 0x0100 15662306a36Sopenharmony_ci#define UCC_UART_SUPSMR_UM_MASK 0x00c0 15762306a36Sopenharmony_ci#define UCC_UART_SUPSMR_UM_NORMAL 0x0000 15862306a36Sopenharmony_ci#define UCC_UART_SUPSMR_UM_MAN_MULTI 0x0040 15962306a36Sopenharmony_ci#define UCC_UART_SUPSMR_UM_AUTO_MULTI 0x00c0 16062306a36Sopenharmony_ci#define UCC_UART_SUPSMR_CL_MASK 0x0030 16162306a36Sopenharmony_ci#define UCC_UART_SUPSMR_CL_8 0x0030 16262306a36Sopenharmony_ci#define UCC_UART_SUPSMR_CL_7 0x0020 16362306a36Sopenharmony_ci#define UCC_UART_SUPSMR_CL_6 0x0010 16462306a36Sopenharmony_ci#define UCC_UART_SUPSMR_CL_5 0x0000 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci#define UCC_UART_TX_STATE_AHDLC 0x00 16762306a36Sopenharmony_ci#define UCC_UART_TX_STATE_UART 0x01 16862306a36Sopenharmony_ci#define UCC_UART_TX_STATE_X1 0x00 16962306a36Sopenharmony_ci#define UCC_UART_TX_STATE_X16 0x80 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci#define UCC_UART_PRAM_ALIGNMENT 0x100 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci#define UCC_UART_SIZE_OF_BD UCC_SLOW_SIZE_OF_BD 17462306a36Sopenharmony_ci#define NUM_CONTROL_CHARS 8 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci/* Private per-port data structure */ 17762306a36Sopenharmony_cistruct uart_qe_port { 17862306a36Sopenharmony_ci struct uart_port port; 17962306a36Sopenharmony_ci struct ucc_slow __iomem *uccp; 18062306a36Sopenharmony_ci struct ucc_uart_pram __iomem *uccup; 18162306a36Sopenharmony_ci struct ucc_slow_info us_info; 18262306a36Sopenharmony_ci struct ucc_slow_private *us_private; 18362306a36Sopenharmony_ci struct device_node *np; 18462306a36Sopenharmony_ci unsigned int ucc_num; /* First ucc is 0, not 1 */ 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci u16 rx_nrfifos; 18762306a36Sopenharmony_ci u16 rx_fifosize; 18862306a36Sopenharmony_ci u16 tx_nrfifos; 18962306a36Sopenharmony_ci u16 tx_fifosize; 19062306a36Sopenharmony_ci int wait_closing; 19162306a36Sopenharmony_ci u32 flags; 19262306a36Sopenharmony_ci struct qe_bd *rx_bd_base; 19362306a36Sopenharmony_ci struct qe_bd *rx_cur; 19462306a36Sopenharmony_ci struct qe_bd *tx_bd_base; 19562306a36Sopenharmony_ci struct qe_bd *tx_cur; 19662306a36Sopenharmony_ci unsigned char *tx_buf; 19762306a36Sopenharmony_ci unsigned char *rx_buf; 19862306a36Sopenharmony_ci void *bd_virt; /* virtual address of the BD buffers */ 19962306a36Sopenharmony_ci dma_addr_t bd_dma_addr; /* bus address of the BD buffers */ 20062306a36Sopenharmony_ci unsigned int bd_size; /* size of BD buffer space */ 20162306a36Sopenharmony_ci}; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic struct uart_driver ucc_uart_driver = { 20462306a36Sopenharmony_ci .owner = THIS_MODULE, 20562306a36Sopenharmony_ci .driver_name = "ucc_uart", 20662306a36Sopenharmony_ci .dev_name = "ttyQE", 20762306a36Sopenharmony_ci .major = SERIAL_QE_MAJOR, 20862306a36Sopenharmony_ci .minor = SERIAL_QE_MINOR, 20962306a36Sopenharmony_ci .nr = UCC_MAX_UART, 21062306a36Sopenharmony_ci}; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci/* 21362306a36Sopenharmony_ci * Virtual to physical address translation. 21462306a36Sopenharmony_ci * 21562306a36Sopenharmony_ci * Given the virtual address for a character buffer, this function returns 21662306a36Sopenharmony_ci * the physical (DMA) equivalent. 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_cistatic inline dma_addr_t cpu2qe_addr(void *addr, struct uart_qe_port *qe_port) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci if (likely((addr >= qe_port->bd_virt)) && 22162306a36Sopenharmony_ci (addr < (qe_port->bd_virt + qe_port->bd_size))) 22262306a36Sopenharmony_ci return qe_port->bd_dma_addr + (addr - qe_port->bd_virt); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* something nasty happened */ 22562306a36Sopenharmony_ci printk(KERN_ERR "%s: addr=%p\n", __func__, addr); 22662306a36Sopenharmony_ci BUG(); 22762306a36Sopenharmony_ci return 0; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci/* 23162306a36Sopenharmony_ci * Physical to virtual address translation. 23262306a36Sopenharmony_ci * 23362306a36Sopenharmony_ci * Given the physical (DMA) address for a character buffer, this function 23462306a36Sopenharmony_ci * returns the virtual equivalent. 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_cistatic inline void *qe2cpu_addr(dma_addr_t addr, struct uart_qe_port *qe_port) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci /* sanity check */ 23962306a36Sopenharmony_ci if (likely((addr >= qe_port->bd_dma_addr) && 24062306a36Sopenharmony_ci (addr < (qe_port->bd_dma_addr + qe_port->bd_size)))) 24162306a36Sopenharmony_ci return qe_port->bd_virt + (addr - qe_port->bd_dma_addr); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci /* something nasty happened */ 24462306a36Sopenharmony_ci printk(KERN_ERR "%s: addr=%llx\n", __func__, (u64)addr); 24562306a36Sopenharmony_ci BUG(); 24662306a36Sopenharmony_ci return NULL; 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci/* 25062306a36Sopenharmony_ci * Return 1 if the QE is done transmitting all buffers for this port 25162306a36Sopenharmony_ci * 25262306a36Sopenharmony_ci * This function scans each BD in sequence. If we find a BD that is not 25362306a36Sopenharmony_ci * ready (READY=1), then we return 0 indicating that the QE is still sending 25462306a36Sopenharmony_ci * data. If we reach the last BD (WRAP=1), then we know we've scanned 25562306a36Sopenharmony_ci * the entire list, and all BDs are done. 25662306a36Sopenharmony_ci */ 25762306a36Sopenharmony_cistatic unsigned int qe_uart_tx_empty(struct uart_port *port) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci struct uart_qe_port *qe_port = 26062306a36Sopenharmony_ci container_of(port, struct uart_qe_port, port); 26162306a36Sopenharmony_ci struct qe_bd *bdp = qe_port->tx_bd_base; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci while (1) { 26462306a36Sopenharmony_ci if (ioread16be(&bdp->status) & BD_SC_READY) 26562306a36Sopenharmony_ci /* This BD is not done, so return "not done" */ 26662306a36Sopenharmony_ci return 0; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (ioread16be(&bdp->status) & BD_SC_WRAP) 26962306a36Sopenharmony_ci /* 27062306a36Sopenharmony_ci * This BD is done and it's the last one, so return 27162306a36Sopenharmony_ci * "done" 27262306a36Sopenharmony_ci */ 27362306a36Sopenharmony_ci return 1; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci bdp++; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci/* 28062306a36Sopenharmony_ci * Set the modem control lines 28162306a36Sopenharmony_ci * 28262306a36Sopenharmony_ci * Although the QE can control the modem control lines (e.g. CTS), we 28362306a36Sopenharmony_ci * don't need that support. This function must exist, however, otherwise 28462306a36Sopenharmony_ci * the kernel will panic. 28562306a36Sopenharmony_ci */ 28662306a36Sopenharmony_cistatic void qe_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci/* 29162306a36Sopenharmony_ci * Get the current modem control line status 29262306a36Sopenharmony_ci * 29362306a36Sopenharmony_ci * Although the QE can control the modem control lines (e.g. CTS), this 29462306a36Sopenharmony_ci * driver currently doesn't support that, so we always return Carrier 29562306a36Sopenharmony_ci * Detect, Data Set Ready, and Clear To Send. 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_cistatic unsigned int qe_uart_get_mctrl(struct uart_port *port) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci/* 30362306a36Sopenharmony_ci * Disable the transmit interrupt. 30462306a36Sopenharmony_ci * 30562306a36Sopenharmony_ci * Although this function is called "stop_tx", it does not actually stop 30662306a36Sopenharmony_ci * transmission of data. Instead, it tells the QE to not generate an 30762306a36Sopenharmony_ci * interrupt when the UCC is finished sending characters. 30862306a36Sopenharmony_ci */ 30962306a36Sopenharmony_cistatic void qe_uart_stop_tx(struct uart_port *port) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci struct uart_qe_port *qe_port = 31262306a36Sopenharmony_ci container_of(port, struct uart_qe_port, port); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci qe_clrbits_be16(&qe_port->uccp->uccm, UCC_UART_UCCE_TX); 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci/* 31862306a36Sopenharmony_ci * Transmit as many characters to the HW as possible. 31962306a36Sopenharmony_ci * 32062306a36Sopenharmony_ci * This function will attempt to stuff of all the characters from the 32162306a36Sopenharmony_ci * kernel's transmit buffer into TX BDs. 32262306a36Sopenharmony_ci * 32362306a36Sopenharmony_ci * A return value of non-zero indicates that it successfully stuffed all 32462306a36Sopenharmony_ci * characters from the kernel buffer. 32562306a36Sopenharmony_ci * 32662306a36Sopenharmony_ci * A return value of zero indicates that there are still characters in the 32762306a36Sopenharmony_ci * kernel's buffer that have not been transmitted, but there are no more BDs 32862306a36Sopenharmony_ci * available. This function should be called again after a BD has been made 32962306a36Sopenharmony_ci * available. 33062306a36Sopenharmony_ci */ 33162306a36Sopenharmony_cistatic int qe_uart_tx_pump(struct uart_qe_port *qe_port) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci struct qe_bd *bdp; 33462306a36Sopenharmony_ci unsigned char *p; 33562306a36Sopenharmony_ci unsigned int count; 33662306a36Sopenharmony_ci struct uart_port *port = &qe_port->port; 33762306a36Sopenharmony_ci struct circ_buf *xmit = &port->state->xmit; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* Handle xon/xoff */ 34062306a36Sopenharmony_ci if (port->x_char) { 34162306a36Sopenharmony_ci /* Pick next descriptor and fill from buffer */ 34262306a36Sopenharmony_ci bdp = qe_port->tx_cur; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci p = qe2cpu_addr(be32_to_cpu(bdp->buf), qe_port); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci *p++ = port->x_char; 34762306a36Sopenharmony_ci iowrite16be(1, &bdp->length); 34862306a36Sopenharmony_ci qe_setbits_be16(&bdp->status, BD_SC_READY); 34962306a36Sopenharmony_ci /* Get next BD. */ 35062306a36Sopenharmony_ci if (ioread16be(&bdp->status) & BD_SC_WRAP) 35162306a36Sopenharmony_ci bdp = qe_port->tx_bd_base; 35262306a36Sopenharmony_ci else 35362306a36Sopenharmony_ci bdp++; 35462306a36Sopenharmony_ci qe_port->tx_cur = bdp; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci port->icount.tx++; 35762306a36Sopenharmony_ci port->x_char = 0; 35862306a36Sopenharmony_ci return 1; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { 36262306a36Sopenharmony_ci qe_uart_stop_tx(port); 36362306a36Sopenharmony_ci return 0; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci /* Pick next descriptor and fill from buffer */ 36762306a36Sopenharmony_ci bdp = qe_port->tx_cur; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci while (!(ioread16be(&bdp->status) & BD_SC_READY) && !uart_circ_empty(xmit)) { 37062306a36Sopenharmony_ci count = 0; 37162306a36Sopenharmony_ci p = qe2cpu_addr(be32_to_cpu(bdp->buf), qe_port); 37262306a36Sopenharmony_ci while (count < qe_port->tx_fifosize) { 37362306a36Sopenharmony_ci *p++ = xmit->buf[xmit->tail]; 37462306a36Sopenharmony_ci uart_xmit_advance(port, 1); 37562306a36Sopenharmony_ci count++; 37662306a36Sopenharmony_ci if (uart_circ_empty(xmit)) 37762306a36Sopenharmony_ci break; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci iowrite16be(count, &bdp->length); 38162306a36Sopenharmony_ci qe_setbits_be16(&bdp->status, BD_SC_READY); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* Get next BD. */ 38462306a36Sopenharmony_ci if (ioread16be(&bdp->status) & BD_SC_WRAP) 38562306a36Sopenharmony_ci bdp = qe_port->tx_bd_base; 38662306a36Sopenharmony_ci else 38762306a36Sopenharmony_ci bdp++; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci qe_port->tx_cur = bdp; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 39262306a36Sopenharmony_ci uart_write_wakeup(port); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (uart_circ_empty(xmit)) { 39562306a36Sopenharmony_ci /* The kernel buffer is empty, so turn off TX interrupts. We 39662306a36Sopenharmony_ci don't need to be told when the QE is finished transmitting 39762306a36Sopenharmony_ci the data. */ 39862306a36Sopenharmony_ci qe_uart_stop_tx(port); 39962306a36Sopenharmony_ci return 0; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci return 1; 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci/* 40662306a36Sopenharmony_ci * Start transmitting data 40762306a36Sopenharmony_ci * 40862306a36Sopenharmony_ci * This function will start transmitting any available data, if the port 40962306a36Sopenharmony_ci * isn't already transmitting data. 41062306a36Sopenharmony_ci */ 41162306a36Sopenharmony_cistatic void qe_uart_start_tx(struct uart_port *port) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci struct uart_qe_port *qe_port = 41462306a36Sopenharmony_ci container_of(port, struct uart_qe_port, port); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci /* If we currently are transmitting, then just return */ 41762306a36Sopenharmony_ci if (ioread16be(&qe_port->uccp->uccm) & UCC_UART_UCCE_TX) 41862306a36Sopenharmony_ci return; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci /* Otherwise, pump the port and start transmission */ 42162306a36Sopenharmony_ci if (qe_uart_tx_pump(qe_port)) 42262306a36Sopenharmony_ci qe_setbits_be16(&qe_port->uccp->uccm, UCC_UART_UCCE_TX); 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci/* 42662306a36Sopenharmony_ci * Stop transmitting data 42762306a36Sopenharmony_ci */ 42862306a36Sopenharmony_cistatic void qe_uart_stop_rx(struct uart_port *port) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci struct uart_qe_port *qe_port = 43162306a36Sopenharmony_ci container_of(port, struct uart_qe_port, port); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci qe_clrbits_be16(&qe_port->uccp->uccm, UCC_UART_UCCE_RX); 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci/* Start or stop sending break signal 43762306a36Sopenharmony_ci * 43862306a36Sopenharmony_ci * This function controls the sending of a break signal. If break_state=1, 43962306a36Sopenharmony_ci * then we start sending a break signal. If break_state=0, then we stop 44062306a36Sopenharmony_ci * sending the break signal. 44162306a36Sopenharmony_ci */ 44262306a36Sopenharmony_cistatic void qe_uart_break_ctl(struct uart_port *port, int break_state) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci struct uart_qe_port *qe_port = 44562306a36Sopenharmony_ci container_of(port, struct uart_qe_port, port); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (break_state) 44862306a36Sopenharmony_ci ucc_slow_stop_tx(qe_port->us_private); 44962306a36Sopenharmony_ci else 45062306a36Sopenharmony_ci ucc_slow_restart_tx(qe_port->us_private); 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci/* ISR helper function for receiving character. 45462306a36Sopenharmony_ci * 45562306a36Sopenharmony_ci * This function is called by the ISR to handling receiving characters 45662306a36Sopenharmony_ci */ 45762306a36Sopenharmony_cistatic void qe_uart_int_rx(struct uart_qe_port *qe_port) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci int i; 46062306a36Sopenharmony_ci unsigned char ch, *cp; 46162306a36Sopenharmony_ci struct uart_port *port = &qe_port->port; 46262306a36Sopenharmony_ci struct tty_port *tport = &port->state->port; 46362306a36Sopenharmony_ci struct qe_bd *bdp; 46462306a36Sopenharmony_ci u16 status; 46562306a36Sopenharmony_ci unsigned int flg; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci /* Just loop through the closed BDs and copy the characters into 46862306a36Sopenharmony_ci * the buffer. 46962306a36Sopenharmony_ci */ 47062306a36Sopenharmony_ci bdp = qe_port->rx_cur; 47162306a36Sopenharmony_ci while (1) { 47262306a36Sopenharmony_ci status = ioread16be(&bdp->status); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci /* If this one is empty, then we assume we've read them all */ 47562306a36Sopenharmony_ci if (status & BD_SC_EMPTY) 47662306a36Sopenharmony_ci break; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci /* get number of characters, and check space in RX buffer */ 47962306a36Sopenharmony_ci i = ioread16be(&bdp->length); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci /* If we don't have enough room in RX buffer for the entire BD, 48262306a36Sopenharmony_ci * then we try later, which will be the next RX interrupt. 48362306a36Sopenharmony_ci */ 48462306a36Sopenharmony_ci if (tty_buffer_request_room(tport, i) < i) { 48562306a36Sopenharmony_ci dev_dbg(port->dev, "ucc-uart: no room in RX buffer\n"); 48662306a36Sopenharmony_ci return; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci /* get pointer */ 49062306a36Sopenharmony_ci cp = qe2cpu_addr(be32_to_cpu(bdp->buf), qe_port); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* loop through the buffer */ 49362306a36Sopenharmony_ci while (i-- > 0) { 49462306a36Sopenharmony_ci ch = *cp++; 49562306a36Sopenharmony_ci port->icount.rx++; 49662306a36Sopenharmony_ci flg = TTY_NORMAL; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (!i && status & 49962306a36Sopenharmony_ci (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV)) 50062306a36Sopenharmony_ci goto handle_error; 50162306a36Sopenharmony_ci if (uart_handle_sysrq_char(port, ch)) 50262306a36Sopenharmony_ci continue; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cierror_return: 50562306a36Sopenharmony_ci tty_insert_flip_char(tport, ch, flg); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* This BD is ready to be used again. Clear status. get next */ 51062306a36Sopenharmony_ci qe_clrsetbits_be16(&bdp->status, 51162306a36Sopenharmony_ci BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV | BD_SC_ID, 51262306a36Sopenharmony_ci BD_SC_EMPTY); 51362306a36Sopenharmony_ci if (ioread16be(&bdp->status) & BD_SC_WRAP) 51462306a36Sopenharmony_ci bdp = qe_port->rx_bd_base; 51562306a36Sopenharmony_ci else 51662306a36Sopenharmony_ci bdp++; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* Write back buffer pointer */ 52162306a36Sopenharmony_ci qe_port->rx_cur = bdp; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci /* Activate BH processing */ 52462306a36Sopenharmony_ci tty_flip_buffer_push(tport); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci return; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci /* Error processing */ 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cihandle_error: 53162306a36Sopenharmony_ci /* Statistics */ 53262306a36Sopenharmony_ci if (status & BD_SC_BR) 53362306a36Sopenharmony_ci port->icount.brk++; 53462306a36Sopenharmony_ci if (status & BD_SC_PR) 53562306a36Sopenharmony_ci port->icount.parity++; 53662306a36Sopenharmony_ci if (status & BD_SC_FR) 53762306a36Sopenharmony_ci port->icount.frame++; 53862306a36Sopenharmony_ci if (status & BD_SC_OV) 53962306a36Sopenharmony_ci port->icount.overrun++; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci /* Mask out ignored conditions */ 54262306a36Sopenharmony_ci status &= port->read_status_mask; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci /* Handle the remaining ones */ 54562306a36Sopenharmony_ci if (status & BD_SC_BR) 54662306a36Sopenharmony_ci flg = TTY_BREAK; 54762306a36Sopenharmony_ci else if (status & BD_SC_PR) 54862306a36Sopenharmony_ci flg = TTY_PARITY; 54962306a36Sopenharmony_ci else if (status & BD_SC_FR) 55062306a36Sopenharmony_ci flg = TTY_FRAME; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci /* Overrun does not affect the current character ! */ 55362306a36Sopenharmony_ci if (status & BD_SC_OV) 55462306a36Sopenharmony_ci tty_insert_flip_char(tport, 0, TTY_OVERRUN); 55562306a36Sopenharmony_ci port->sysrq = 0; 55662306a36Sopenharmony_ci goto error_return; 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci/* Interrupt handler 56062306a36Sopenharmony_ci * 56162306a36Sopenharmony_ci * This interrupt handler is called after a BD is processed. 56262306a36Sopenharmony_ci */ 56362306a36Sopenharmony_cistatic irqreturn_t qe_uart_int(int irq, void *data) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci struct uart_qe_port *qe_port = (struct uart_qe_port *) data; 56662306a36Sopenharmony_ci struct ucc_slow __iomem *uccp = qe_port->uccp; 56762306a36Sopenharmony_ci u16 events; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci /* Clear the interrupts */ 57062306a36Sopenharmony_ci events = ioread16be(&uccp->ucce); 57162306a36Sopenharmony_ci iowrite16be(events, &uccp->ucce); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (events & UCC_UART_UCCE_BRKE) 57462306a36Sopenharmony_ci uart_handle_break(&qe_port->port); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (events & UCC_UART_UCCE_RX) 57762306a36Sopenharmony_ci qe_uart_int_rx(qe_port); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci if (events & UCC_UART_UCCE_TX) 58062306a36Sopenharmony_ci qe_uart_tx_pump(qe_port); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci return events ? IRQ_HANDLED : IRQ_NONE; 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci/* Initialize buffer descriptors 58662306a36Sopenharmony_ci * 58762306a36Sopenharmony_ci * This function initializes all of the RX and TX buffer descriptors. 58862306a36Sopenharmony_ci */ 58962306a36Sopenharmony_cistatic void qe_uart_initbd(struct uart_qe_port *qe_port) 59062306a36Sopenharmony_ci{ 59162306a36Sopenharmony_ci int i; 59262306a36Sopenharmony_ci void *bd_virt; 59362306a36Sopenharmony_ci struct qe_bd *bdp; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci /* Set the physical address of the host memory buffers in the buffer 59662306a36Sopenharmony_ci * descriptors, and the virtual address for us to work with. 59762306a36Sopenharmony_ci */ 59862306a36Sopenharmony_ci bd_virt = qe_port->bd_virt; 59962306a36Sopenharmony_ci bdp = qe_port->rx_bd_base; 60062306a36Sopenharmony_ci qe_port->rx_cur = qe_port->rx_bd_base; 60162306a36Sopenharmony_ci for (i = 0; i < (qe_port->rx_nrfifos - 1); i++) { 60262306a36Sopenharmony_ci iowrite16be(BD_SC_EMPTY | BD_SC_INTRPT, &bdp->status); 60362306a36Sopenharmony_ci iowrite32be(cpu2qe_addr(bd_virt, qe_port), &bdp->buf); 60462306a36Sopenharmony_ci iowrite16be(0, &bdp->length); 60562306a36Sopenharmony_ci bd_virt += qe_port->rx_fifosize; 60662306a36Sopenharmony_ci bdp++; 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci /* */ 61062306a36Sopenharmony_ci iowrite16be(BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT, &bdp->status); 61162306a36Sopenharmony_ci iowrite32be(cpu2qe_addr(bd_virt, qe_port), &bdp->buf); 61262306a36Sopenharmony_ci iowrite16be(0, &bdp->length); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci /* Set the physical address of the host memory 61562306a36Sopenharmony_ci * buffers in the buffer descriptors, and the 61662306a36Sopenharmony_ci * virtual address for us to work with. 61762306a36Sopenharmony_ci */ 61862306a36Sopenharmony_ci bd_virt = qe_port->bd_virt + 61962306a36Sopenharmony_ci L1_CACHE_ALIGN(qe_port->rx_nrfifos * qe_port->rx_fifosize); 62062306a36Sopenharmony_ci qe_port->tx_cur = qe_port->tx_bd_base; 62162306a36Sopenharmony_ci bdp = qe_port->tx_bd_base; 62262306a36Sopenharmony_ci for (i = 0; i < (qe_port->tx_nrfifos - 1); i++) { 62362306a36Sopenharmony_ci iowrite16be(BD_SC_INTRPT, &bdp->status); 62462306a36Sopenharmony_ci iowrite32be(cpu2qe_addr(bd_virt, qe_port), &bdp->buf); 62562306a36Sopenharmony_ci iowrite16be(0, &bdp->length); 62662306a36Sopenharmony_ci bd_virt += qe_port->tx_fifosize; 62762306a36Sopenharmony_ci bdp++; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci /* Loopback requires the preamble bit to be set on the first TX BD */ 63162306a36Sopenharmony_ci#ifdef LOOPBACK 63262306a36Sopenharmony_ci qe_setbits_be16(&qe_port->tx_cur->status, BD_SC_P); 63362306a36Sopenharmony_ci#endif 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci iowrite16be(BD_SC_WRAP | BD_SC_INTRPT, &bdp->status); 63662306a36Sopenharmony_ci iowrite32be(cpu2qe_addr(bd_virt, qe_port), &bdp->buf); 63762306a36Sopenharmony_ci iowrite16be(0, &bdp->length); 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci/* 64162306a36Sopenharmony_ci * Initialize a UCC for UART. 64262306a36Sopenharmony_ci * 64362306a36Sopenharmony_ci * This function configures a given UCC to be used as a UART device. Basic 64462306a36Sopenharmony_ci * UCC initialization is handled in qe_uart_request_port(). This function 64562306a36Sopenharmony_ci * does all the UART-specific stuff. 64662306a36Sopenharmony_ci */ 64762306a36Sopenharmony_cistatic void qe_uart_init_ucc(struct uart_qe_port *qe_port) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci u32 cecr_subblock; 65062306a36Sopenharmony_ci struct ucc_slow __iomem *uccp = qe_port->uccp; 65162306a36Sopenharmony_ci struct ucc_uart_pram *uccup = qe_port->uccup; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci unsigned int i; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci /* First, disable TX and RX in the UCC */ 65662306a36Sopenharmony_ci ucc_slow_disable(qe_port->us_private, COMM_DIR_RX_AND_TX); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci /* Program the UCC UART parameter RAM */ 65962306a36Sopenharmony_ci iowrite8(UCC_BMR_GBL | UCC_BMR_BO_BE, &uccup->common.rbmr); 66062306a36Sopenharmony_ci iowrite8(UCC_BMR_GBL | UCC_BMR_BO_BE, &uccup->common.tbmr); 66162306a36Sopenharmony_ci iowrite16be(qe_port->rx_fifosize, &uccup->common.mrblr); 66262306a36Sopenharmony_ci iowrite16be(0x10, &uccup->maxidl); 66362306a36Sopenharmony_ci iowrite16be(1, &uccup->brkcr); 66462306a36Sopenharmony_ci iowrite16be(0, &uccup->parec); 66562306a36Sopenharmony_ci iowrite16be(0, &uccup->frmec); 66662306a36Sopenharmony_ci iowrite16be(0, &uccup->nosec); 66762306a36Sopenharmony_ci iowrite16be(0, &uccup->brkec); 66862306a36Sopenharmony_ci iowrite16be(0, &uccup->uaddr[0]); 66962306a36Sopenharmony_ci iowrite16be(0, &uccup->uaddr[1]); 67062306a36Sopenharmony_ci iowrite16be(0, &uccup->toseq); 67162306a36Sopenharmony_ci for (i = 0; i < 8; i++) 67262306a36Sopenharmony_ci iowrite16be(0xC000, &uccup->cchars[i]); 67362306a36Sopenharmony_ci iowrite16be(0xc0ff, &uccup->rccm); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* Configure the GUMR registers for UART */ 67662306a36Sopenharmony_ci if (soft_uart) { 67762306a36Sopenharmony_ci /* Soft-UART requires a 1X multiplier for TX */ 67862306a36Sopenharmony_ci qe_clrsetbits_be32(&uccp->gumr_l, 67962306a36Sopenharmony_ci UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK | UCC_SLOW_GUMR_L_RDCR_MASK, 68062306a36Sopenharmony_ci UCC_SLOW_GUMR_L_MODE_UART | UCC_SLOW_GUMR_L_TDCR_1 | UCC_SLOW_GUMR_L_RDCR_16); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci qe_clrsetbits_be32(&uccp->gumr_h, UCC_SLOW_GUMR_H_RFW, 68362306a36Sopenharmony_ci UCC_SLOW_GUMR_H_TRX | UCC_SLOW_GUMR_H_TTX); 68462306a36Sopenharmony_ci } else { 68562306a36Sopenharmony_ci qe_clrsetbits_be32(&uccp->gumr_l, 68662306a36Sopenharmony_ci UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK | UCC_SLOW_GUMR_L_RDCR_MASK, 68762306a36Sopenharmony_ci UCC_SLOW_GUMR_L_MODE_UART | UCC_SLOW_GUMR_L_TDCR_16 | UCC_SLOW_GUMR_L_RDCR_16); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci qe_clrsetbits_be32(&uccp->gumr_h, 69062306a36Sopenharmony_ci UCC_SLOW_GUMR_H_TRX | UCC_SLOW_GUMR_H_TTX, 69162306a36Sopenharmony_ci UCC_SLOW_GUMR_H_RFW); 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci#ifdef LOOPBACK 69562306a36Sopenharmony_ci qe_clrsetbits_be32(&uccp->gumr_l, UCC_SLOW_GUMR_L_DIAG_MASK, 69662306a36Sopenharmony_ci UCC_SLOW_GUMR_L_DIAG_LOOP); 69762306a36Sopenharmony_ci qe_clrsetbits_be32(&uccp->gumr_h, 69862306a36Sopenharmony_ci UCC_SLOW_GUMR_H_CTSP | UCC_SLOW_GUMR_H_RSYN, 69962306a36Sopenharmony_ci UCC_SLOW_GUMR_H_CDS); 70062306a36Sopenharmony_ci#endif 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci /* Disable rx interrupts and clear all pending events. */ 70362306a36Sopenharmony_ci iowrite16be(0, &uccp->uccm); 70462306a36Sopenharmony_ci iowrite16be(0xffff, &uccp->ucce); 70562306a36Sopenharmony_ci iowrite16be(0x7e7e, &uccp->udsr); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci /* Initialize UPSMR */ 70862306a36Sopenharmony_ci iowrite16be(0, &uccp->upsmr); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if (soft_uart) { 71162306a36Sopenharmony_ci iowrite16be(0x30, &uccup->supsmr); 71262306a36Sopenharmony_ci iowrite16be(0, &uccup->res92); 71362306a36Sopenharmony_ci iowrite32be(0, &uccup->rx_state); 71462306a36Sopenharmony_ci iowrite32be(0, &uccup->rx_cnt); 71562306a36Sopenharmony_ci iowrite8(0, &uccup->rx_bitmark); 71662306a36Sopenharmony_ci iowrite8(10, &uccup->rx_length); 71762306a36Sopenharmony_ci iowrite32be(0x4000, &uccup->dump_ptr); 71862306a36Sopenharmony_ci iowrite8(0, &uccup->rx_temp_dlst_qe); 71962306a36Sopenharmony_ci iowrite32be(0, &uccup->rx_frame_rem); 72062306a36Sopenharmony_ci iowrite8(0, &uccup->rx_frame_rem_size); 72162306a36Sopenharmony_ci /* Soft-UART requires TX to be 1X */ 72262306a36Sopenharmony_ci iowrite8(UCC_UART_TX_STATE_UART | UCC_UART_TX_STATE_X1, 72362306a36Sopenharmony_ci &uccup->tx_mode); 72462306a36Sopenharmony_ci iowrite16be(0, &uccup->tx_state); 72562306a36Sopenharmony_ci iowrite8(0, &uccup->resD4); 72662306a36Sopenharmony_ci iowrite16be(0, &uccup->resD5); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci /* Set UART mode. 72962306a36Sopenharmony_ci * Enable receive and transmit. 73062306a36Sopenharmony_ci */ 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci /* From the microcode errata: 73362306a36Sopenharmony_ci * 1.GUMR_L register, set mode=0010 (QMC). 73462306a36Sopenharmony_ci * 2.Set GUMR_H[17] bit. (UART/AHDLC mode). 73562306a36Sopenharmony_ci * 3.Set GUMR_H[19:20] (Transparent mode) 73662306a36Sopenharmony_ci * 4.Clear GUMR_H[26] (RFW) 73762306a36Sopenharmony_ci * ... 73862306a36Sopenharmony_ci * 6.Receiver must use 16x over sampling 73962306a36Sopenharmony_ci */ 74062306a36Sopenharmony_ci qe_clrsetbits_be32(&uccp->gumr_l, 74162306a36Sopenharmony_ci UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK | UCC_SLOW_GUMR_L_RDCR_MASK, 74262306a36Sopenharmony_ci UCC_SLOW_GUMR_L_MODE_QMC | UCC_SLOW_GUMR_L_TDCR_16 | UCC_SLOW_GUMR_L_RDCR_16); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci qe_clrsetbits_be32(&uccp->gumr_h, 74562306a36Sopenharmony_ci UCC_SLOW_GUMR_H_RFW | UCC_SLOW_GUMR_H_RSYN, 74662306a36Sopenharmony_ci UCC_SLOW_GUMR_H_SUART | UCC_SLOW_GUMR_H_TRX | UCC_SLOW_GUMR_H_TTX | UCC_SLOW_GUMR_H_TFL); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci#ifdef LOOPBACK 74962306a36Sopenharmony_ci qe_clrsetbits_be32(&uccp->gumr_l, UCC_SLOW_GUMR_L_DIAG_MASK, 75062306a36Sopenharmony_ci UCC_SLOW_GUMR_L_DIAG_LOOP); 75162306a36Sopenharmony_ci qe_clrbits_be32(&uccp->gumr_h, 75262306a36Sopenharmony_ci UCC_SLOW_GUMR_H_CTSP | UCC_SLOW_GUMR_H_CDS); 75362306a36Sopenharmony_ci#endif 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci cecr_subblock = ucc_slow_get_qe_cr_subblock(qe_port->ucc_num); 75662306a36Sopenharmony_ci qe_issue_cmd(QE_INIT_TX_RX, cecr_subblock, 75762306a36Sopenharmony_ci QE_CR_PROTOCOL_UNSPECIFIED, 0); 75862306a36Sopenharmony_ci } else { 75962306a36Sopenharmony_ci cecr_subblock = ucc_slow_get_qe_cr_subblock(qe_port->ucc_num); 76062306a36Sopenharmony_ci qe_issue_cmd(QE_INIT_TX_RX, cecr_subblock, 76162306a36Sopenharmony_ci QE_CR_PROTOCOL_UART, 0); 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci} 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci/* 76662306a36Sopenharmony_ci * Initialize the port. 76762306a36Sopenharmony_ci */ 76862306a36Sopenharmony_cistatic int qe_uart_startup(struct uart_port *port) 76962306a36Sopenharmony_ci{ 77062306a36Sopenharmony_ci struct uart_qe_port *qe_port = 77162306a36Sopenharmony_ci container_of(port, struct uart_qe_port, port); 77262306a36Sopenharmony_ci int ret; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci /* 77562306a36Sopenharmony_ci * If we're using Soft-UART mode, then we need to make sure the 77662306a36Sopenharmony_ci * firmware has been uploaded first. 77762306a36Sopenharmony_ci */ 77862306a36Sopenharmony_ci if (soft_uart && !firmware_loaded) { 77962306a36Sopenharmony_ci dev_err(port->dev, "Soft-UART firmware not uploaded\n"); 78062306a36Sopenharmony_ci return -ENODEV; 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci qe_uart_initbd(qe_port); 78462306a36Sopenharmony_ci qe_uart_init_ucc(qe_port); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci /* Install interrupt handler. */ 78762306a36Sopenharmony_ci ret = request_irq(port->irq, qe_uart_int, IRQF_SHARED, "ucc-uart", 78862306a36Sopenharmony_ci qe_port); 78962306a36Sopenharmony_ci if (ret) { 79062306a36Sopenharmony_ci dev_err(port->dev, "could not claim IRQ %u\n", port->irq); 79162306a36Sopenharmony_ci return ret; 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci /* Startup rx-int */ 79562306a36Sopenharmony_ci qe_setbits_be16(&qe_port->uccp->uccm, UCC_UART_UCCE_RX); 79662306a36Sopenharmony_ci ucc_slow_enable(qe_port->us_private, COMM_DIR_RX_AND_TX); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci return 0; 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci/* 80262306a36Sopenharmony_ci * Shutdown the port. 80362306a36Sopenharmony_ci */ 80462306a36Sopenharmony_cistatic void qe_uart_shutdown(struct uart_port *port) 80562306a36Sopenharmony_ci{ 80662306a36Sopenharmony_ci struct uart_qe_port *qe_port = 80762306a36Sopenharmony_ci container_of(port, struct uart_qe_port, port); 80862306a36Sopenharmony_ci struct ucc_slow __iomem *uccp = qe_port->uccp; 80962306a36Sopenharmony_ci unsigned int timeout = 20; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci /* Disable RX and TX */ 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci /* Wait for all the BDs marked sent */ 81462306a36Sopenharmony_ci while (!qe_uart_tx_empty(port)) { 81562306a36Sopenharmony_ci if (!--timeout) { 81662306a36Sopenharmony_ci dev_warn(port->dev, "shutdown timeout\n"); 81762306a36Sopenharmony_ci break; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 82062306a36Sopenharmony_ci schedule_timeout(2); 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci if (qe_port->wait_closing) { 82462306a36Sopenharmony_ci /* Wait a bit longer */ 82562306a36Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 82662306a36Sopenharmony_ci schedule_timeout(qe_port->wait_closing); 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci /* Stop uarts */ 83062306a36Sopenharmony_ci ucc_slow_disable(qe_port->us_private, COMM_DIR_RX_AND_TX); 83162306a36Sopenharmony_ci qe_clrbits_be16(&uccp->uccm, UCC_UART_UCCE_TX | UCC_UART_UCCE_RX); 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci /* Shut them really down and reinit buffer descriptors */ 83462306a36Sopenharmony_ci ucc_slow_graceful_stop_tx(qe_port->us_private); 83562306a36Sopenharmony_ci qe_uart_initbd(qe_port); 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci free_irq(port->irq, qe_port); 83862306a36Sopenharmony_ci} 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci/* 84162306a36Sopenharmony_ci * Set the serial port parameters. 84262306a36Sopenharmony_ci */ 84362306a36Sopenharmony_cistatic void qe_uart_set_termios(struct uart_port *port, 84462306a36Sopenharmony_ci struct ktermios *termios, 84562306a36Sopenharmony_ci const struct ktermios *old) 84662306a36Sopenharmony_ci{ 84762306a36Sopenharmony_ci struct uart_qe_port *qe_port = 84862306a36Sopenharmony_ci container_of(port, struct uart_qe_port, port); 84962306a36Sopenharmony_ci struct ucc_slow __iomem *uccp = qe_port->uccp; 85062306a36Sopenharmony_ci unsigned int baud; 85162306a36Sopenharmony_ci unsigned long flags; 85262306a36Sopenharmony_ci u16 upsmr = ioread16be(&uccp->upsmr); 85362306a36Sopenharmony_ci struct ucc_uart_pram __iomem *uccup = qe_port->uccup; 85462306a36Sopenharmony_ci u16 supsmr = ioread16be(&uccup->supsmr); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci /* byte size */ 85762306a36Sopenharmony_ci upsmr &= UCC_UART_UPSMR_CL_MASK; 85862306a36Sopenharmony_ci supsmr &= UCC_UART_SUPSMR_CL_MASK; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci switch (termios->c_cflag & CSIZE) { 86162306a36Sopenharmony_ci case CS5: 86262306a36Sopenharmony_ci upsmr |= UCC_UART_UPSMR_CL_5; 86362306a36Sopenharmony_ci supsmr |= UCC_UART_SUPSMR_CL_5; 86462306a36Sopenharmony_ci break; 86562306a36Sopenharmony_ci case CS6: 86662306a36Sopenharmony_ci upsmr |= UCC_UART_UPSMR_CL_6; 86762306a36Sopenharmony_ci supsmr |= UCC_UART_SUPSMR_CL_6; 86862306a36Sopenharmony_ci break; 86962306a36Sopenharmony_ci case CS7: 87062306a36Sopenharmony_ci upsmr |= UCC_UART_UPSMR_CL_7; 87162306a36Sopenharmony_ci supsmr |= UCC_UART_SUPSMR_CL_7; 87262306a36Sopenharmony_ci break; 87362306a36Sopenharmony_ci default: /* case CS8 */ 87462306a36Sopenharmony_ci upsmr |= UCC_UART_UPSMR_CL_8; 87562306a36Sopenharmony_ci supsmr |= UCC_UART_SUPSMR_CL_8; 87662306a36Sopenharmony_ci break; 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci /* If CSTOPB is set, we want two stop bits */ 88062306a36Sopenharmony_ci if (termios->c_cflag & CSTOPB) { 88162306a36Sopenharmony_ci upsmr |= UCC_UART_UPSMR_SL; 88262306a36Sopenharmony_ci supsmr |= UCC_UART_SUPSMR_SL; 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci if (termios->c_cflag & PARENB) { 88662306a36Sopenharmony_ci upsmr |= UCC_UART_UPSMR_PEN; 88762306a36Sopenharmony_ci supsmr |= UCC_UART_SUPSMR_PEN; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci if (!(termios->c_cflag & PARODD)) { 89062306a36Sopenharmony_ci upsmr &= ~(UCC_UART_UPSMR_RPM_MASK | 89162306a36Sopenharmony_ci UCC_UART_UPSMR_TPM_MASK); 89262306a36Sopenharmony_ci upsmr |= UCC_UART_UPSMR_RPM_EVEN | 89362306a36Sopenharmony_ci UCC_UART_UPSMR_TPM_EVEN; 89462306a36Sopenharmony_ci supsmr &= ~(UCC_UART_SUPSMR_RPM_MASK | 89562306a36Sopenharmony_ci UCC_UART_SUPSMR_TPM_MASK); 89662306a36Sopenharmony_ci supsmr |= UCC_UART_SUPSMR_RPM_EVEN | 89762306a36Sopenharmony_ci UCC_UART_SUPSMR_TPM_EVEN; 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci } 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci /* 90262306a36Sopenharmony_ci * Set up parity check flag 90362306a36Sopenharmony_ci */ 90462306a36Sopenharmony_ci port->read_status_mask = BD_SC_EMPTY | BD_SC_OV; 90562306a36Sopenharmony_ci if (termios->c_iflag & INPCK) 90662306a36Sopenharmony_ci port->read_status_mask |= BD_SC_FR | BD_SC_PR; 90762306a36Sopenharmony_ci if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 90862306a36Sopenharmony_ci port->read_status_mask |= BD_SC_BR; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci /* 91162306a36Sopenharmony_ci * Characters to ignore 91262306a36Sopenharmony_ci */ 91362306a36Sopenharmony_ci port->ignore_status_mask = 0; 91462306a36Sopenharmony_ci if (termios->c_iflag & IGNPAR) 91562306a36Sopenharmony_ci port->ignore_status_mask |= BD_SC_PR | BD_SC_FR; 91662306a36Sopenharmony_ci if (termios->c_iflag & IGNBRK) { 91762306a36Sopenharmony_ci port->ignore_status_mask |= BD_SC_BR; 91862306a36Sopenharmony_ci /* 91962306a36Sopenharmony_ci * If we're ignore parity and break indicators, ignore 92062306a36Sopenharmony_ci * overruns too. (For real raw support). 92162306a36Sopenharmony_ci */ 92262306a36Sopenharmony_ci if (termios->c_iflag & IGNPAR) 92362306a36Sopenharmony_ci port->ignore_status_mask |= BD_SC_OV; 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci /* 92662306a36Sopenharmony_ci * !!! ignore all characters if CREAD is not set 92762306a36Sopenharmony_ci */ 92862306a36Sopenharmony_ci if ((termios->c_cflag & CREAD) == 0) 92962306a36Sopenharmony_ci port->read_status_mask &= ~BD_SC_EMPTY; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci /* Do we really need a spinlock here? */ 93462306a36Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci /* Update the per-port timeout. */ 93762306a36Sopenharmony_ci uart_update_timeout(port, termios->c_cflag, baud); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci iowrite16be(upsmr, &uccp->upsmr); 94062306a36Sopenharmony_ci if (soft_uart) { 94162306a36Sopenharmony_ci iowrite16be(supsmr, &uccup->supsmr); 94262306a36Sopenharmony_ci iowrite8(tty_get_frame_size(termios->c_cflag), &uccup->rx_length); 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci /* Soft-UART requires a 1X multiplier for TX */ 94562306a36Sopenharmony_ci qe_setbrg(qe_port->us_info.rx_clock, baud, 16); 94662306a36Sopenharmony_ci qe_setbrg(qe_port->us_info.tx_clock, baud, 1); 94762306a36Sopenharmony_ci } else { 94862306a36Sopenharmony_ci qe_setbrg(qe_port->us_info.rx_clock, baud, 16); 94962306a36Sopenharmony_ci qe_setbrg(qe_port->us_info.tx_clock, baud, 16); 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 95362306a36Sopenharmony_ci} 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci/* 95662306a36Sopenharmony_ci * Return a pointer to a string that describes what kind of port this is. 95762306a36Sopenharmony_ci */ 95862306a36Sopenharmony_cistatic const char *qe_uart_type(struct uart_port *port) 95962306a36Sopenharmony_ci{ 96062306a36Sopenharmony_ci return "QE"; 96162306a36Sopenharmony_ci} 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci/* 96462306a36Sopenharmony_ci * Allocate any memory and I/O resources required by the port. 96562306a36Sopenharmony_ci */ 96662306a36Sopenharmony_cistatic int qe_uart_request_port(struct uart_port *port) 96762306a36Sopenharmony_ci{ 96862306a36Sopenharmony_ci int ret; 96962306a36Sopenharmony_ci struct uart_qe_port *qe_port = 97062306a36Sopenharmony_ci container_of(port, struct uart_qe_port, port); 97162306a36Sopenharmony_ci struct ucc_slow_info *us_info = &qe_port->us_info; 97262306a36Sopenharmony_ci struct ucc_slow_private *uccs; 97362306a36Sopenharmony_ci unsigned int rx_size, tx_size; 97462306a36Sopenharmony_ci void *bd_virt; 97562306a36Sopenharmony_ci dma_addr_t bd_dma_addr = 0; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci ret = ucc_slow_init(us_info, &uccs); 97862306a36Sopenharmony_ci if (ret) { 97962306a36Sopenharmony_ci dev_err(port->dev, "could not initialize UCC%u\n", 98062306a36Sopenharmony_ci qe_port->ucc_num); 98162306a36Sopenharmony_ci return ret; 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci qe_port->us_private = uccs; 98562306a36Sopenharmony_ci qe_port->uccp = uccs->us_regs; 98662306a36Sopenharmony_ci qe_port->uccup = (struct ucc_uart_pram *) uccs->us_pram; 98762306a36Sopenharmony_ci qe_port->rx_bd_base = uccs->rx_bd; 98862306a36Sopenharmony_ci qe_port->tx_bd_base = uccs->tx_bd; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci /* 99162306a36Sopenharmony_ci * Allocate the transmit and receive data buffers. 99262306a36Sopenharmony_ci */ 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci rx_size = L1_CACHE_ALIGN(qe_port->rx_nrfifos * qe_port->rx_fifosize); 99562306a36Sopenharmony_ci tx_size = L1_CACHE_ALIGN(qe_port->tx_nrfifos * qe_port->tx_fifosize); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci bd_virt = dma_alloc_coherent(port->dev, rx_size + tx_size, &bd_dma_addr, 99862306a36Sopenharmony_ci GFP_KERNEL); 99962306a36Sopenharmony_ci if (!bd_virt) { 100062306a36Sopenharmony_ci dev_err(port->dev, "could not allocate buffer descriptors\n"); 100162306a36Sopenharmony_ci return -ENOMEM; 100262306a36Sopenharmony_ci } 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci qe_port->bd_virt = bd_virt; 100562306a36Sopenharmony_ci qe_port->bd_dma_addr = bd_dma_addr; 100662306a36Sopenharmony_ci qe_port->bd_size = rx_size + tx_size; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci qe_port->rx_buf = bd_virt; 100962306a36Sopenharmony_ci qe_port->tx_buf = qe_port->rx_buf + rx_size; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci return 0; 101262306a36Sopenharmony_ci} 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci/* 101562306a36Sopenharmony_ci * Configure the port. 101662306a36Sopenharmony_ci * 101762306a36Sopenharmony_ci * We say we're a CPM-type port because that's mostly true. Once the device 101862306a36Sopenharmony_ci * is configured, this driver operates almost identically to the CPM serial 101962306a36Sopenharmony_ci * driver. 102062306a36Sopenharmony_ci */ 102162306a36Sopenharmony_cistatic void qe_uart_config_port(struct uart_port *port, int flags) 102262306a36Sopenharmony_ci{ 102362306a36Sopenharmony_ci if (flags & UART_CONFIG_TYPE) { 102462306a36Sopenharmony_ci port->type = PORT_CPM; 102562306a36Sopenharmony_ci qe_uart_request_port(port); 102662306a36Sopenharmony_ci } 102762306a36Sopenharmony_ci} 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci/* 103062306a36Sopenharmony_ci * Release any memory and I/O resources that were allocated in 103162306a36Sopenharmony_ci * qe_uart_request_port(). 103262306a36Sopenharmony_ci */ 103362306a36Sopenharmony_cistatic void qe_uart_release_port(struct uart_port *port) 103462306a36Sopenharmony_ci{ 103562306a36Sopenharmony_ci struct uart_qe_port *qe_port = 103662306a36Sopenharmony_ci container_of(port, struct uart_qe_port, port); 103762306a36Sopenharmony_ci struct ucc_slow_private *uccs = qe_port->us_private; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci dma_free_coherent(port->dev, qe_port->bd_size, qe_port->bd_virt, 104062306a36Sopenharmony_ci qe_port->bd_dma_addr); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci ucc_slow_free(uccs); 104362306a36Sopenharmony_ci} 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci/* 104662306a36Sopenharmony_ci * Verify that the data in serial_struct is suitable for this device. 104762306a36Sopenharmony_ci */ 104862306a36Sopenharmony_cistatic int qe_uart_verify_port(struct uart_port *port, 104962306a36Sopenharmony_ci struct serial_struct *ser) 105062306a36Sopenharmony_ci{ 105162306a36Sopenharmony_ci if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM) 105262306a36Sopenharmony_ci return -EINVAL; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci if (ser->irq < 0 || ser->irq >= nr_irqs) 105562306a36Sopenharmony_ci return -EINVAL; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci if (ser->baud_base < 9600) 105862306a36Sopenharmony_ci return -EINVAL; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci return 0; 106162306a36Sopenharmony_ci} 106262306a36Sopenharmony_ci/* UART operations 106362306a36Sopenharmony_ci * 106462306a36Sopenharmony_ci * Details on these functions can be found in Documentation/driver-api/serial/driver.rst 106562306a36Sopenharmony_ci */ 106662306a36Sopenharmony_cistatic const struct uart_ops qe_uart_pops = { 106762306a36Sopenharmony_ci .tx_empty = qe_uart_tx_empty, 106862306a36Sopenharmony_ci .set_mctrl = qe_uart_set_mctrl, 106962306a36Sopenharmony_ci .get_mctrl = qe_uart_get_mctrl, 107062306a36Sopenharmony_ci .stop_tx = qe_uart_stop_tx, 107162306a36Sopenharmony_ci .start_tx = qe_uart_start_tx, 107262306a36Sopenharmony_ci .stop_rx = qe_uart_stop_rx, 107362306a36Sopenharmony_ci .break_ctl = qe_uart_break_ctl, 107462306a36Sopenharmony_ci .startup = qe_uart_startup, 107562306a36Sopenharmony_ci .shutdown = qe_uart_shutdown, 107662306a36Sopenharmony_ci .set_termios = qe_uart_set_termios, 107762306a36Sopenharmony_ci .type = qe_uart_type, 107862306a36Sopenharmony_ci .release_port = qe_uart_release_port, 107962306a36Sopenharmony_ci .request_port = qe_uart_request_port, 108062306a36Sopenharmony_ci .config_port = qe_uart_config_port, 108162306a36Sopenharmony_ci .verify_port = qe_uart_verify_port, 108262306a36Sopenharmony_ci}; 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci#ifdef CONFIG_PPC32 108662306a36Sopenharmony_ci/* 108762306a36Sopenharmony_ci * Obtain the SOC model number and revision level 108862306a36Sopenharmony_ci * 108962306a36Sopenharmony_ci * This function parses the device tree to obtain the SOC model. It then 109062306a36Sopenharmony_ci * reads the SVR register to the revision. 109162306a36Sopenharmony_ci * 109262306a36Sopenharmony_ci * The device tree stores the SOC model two different ways. 109362306a36Sopenharmony_ci * 109462306a36Sopenharmony_ci * The new way is: 109562306a36Sopenharmony_ci * 109662306a36Sopenharmony_ci * cpu@0 { 109762306a36Sopenharmony_ci * compatible = "PowerPC,8323"; 109862306a36Sopenharmony_ci * device_type = "cpu"; 109962306a36Sopenharmony_ci * ... 110062306a36Sopenharmony_ci * 110162306a36Sopenharmony_ci * 110262306a36Sopenharmony_ci * The old way is: 110362306a36Sopenharmony_ci * PowerPC,8323@0 { 110462306a36Sopenharmony_ci * device_type = "cpu"; 110562306a36Sopenharmony_ci * ... 110662306a36Sopenharmony_ci * 110762306a36Sopenharmony_ci * This code first checks the new way, and then the old way. 110862306a36Sopenharmony_ci */ 110962306a36Sopenharmony_cistatic unsigned int soc_info(unsigned int *rev_h, unsigned int *rev_l) 111062306a36Sopenharmony_ci{ 111162306a36Sopenharmony_ci struct device_node *np; 111262306a36Sopenharmony_ci const char *soc_string; 111362306a36Sopenharmony_ci unsigned int svr; 111462306a36Sopenharmony_ci unsigned int soc; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci /* Find the CPU node */ 111762306a36Sopenharmony_ci np = of_find_node_by_type(NULL, "cpu"); 111862306a36Sopenharmony_ci if (!np) 111962306a36Sopenharmony_ci return 0; 112062306a36Sopenharmony_ci /* Find the compatible property */ 112162306a36Sopenharmony_ci soc_string = of_get_property(np, "compatible", NULL); 112262306a36Sopenharmony_ci if (!soc_string) 112362306a36Sopenharmony_ci /* No compatible property, so try the name. */ 112462306a36Sopenharmony_ci soc_string = np->name; 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci of_node_put(np); 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci /* Extract the SOC number from the "PowerPC," string */ 112962306a36Sopenharmony_ci if ((sscanf(soc_string, "PowerPC,%u", &soc) != 1) || !soc) 113062306a36Sopenharmony_ci return 0; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci /* Get the revision from the SVR */ 113362306a36Sopenharmony_ci svr = mfspr(SPRN_SVR); 113462306a36Sopenharmony_ci *rev_h = (svr >> 4) & 0xf; 113562306a36Sopenharmony_ci *rev_l = svr & 0xf; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci return soc; 113862306a36Sopenharmony_ci} 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci/* 114162306a36Sopenharmony_ci * requst_firmware_nowait() callback function 114262306a36Sopenharmony_ci * 114362306a36Sopenharmony_ci * This function is called by the kernel when a firmware is made available, 114462306a36Sopenharmony_ci * or if it times out waiting for the firmware. 114562306a36Sopenharmony_ci */ 114662306a36Sopenharmony_cistatic void uart_firmware_cont(const struct firmware *fw, void *context) 114762306a36Sopenharmony_ci{ 114862306a36Sopenharmony_ci struct qe_firmware *firmware; 114962306a36Sopenharmony_ci struct device *dev = context; 115062306a36Sopenharmony_ci int ret; 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci if (!fw) { 115362306a36Sopenharmony_ci dev_err(dev, "firmware not found\n"); 115462306a36Sopenharmony_ci return; 115562306a36Sopenharmony_ci } 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci firmware = (struct qe_firmware *) fw->data; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci if (firmware->header.length != fw->size) { 116062306a36Sopenharmony_ci dev_err(dev, "invalid firmware\n"); 116162306a36Sopenharmony_ci goto out; 116262306a36Sopenharmony_ci } 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci ret = qe_upload_firmware(firmware); 116562306a36Sopenharmony_ci if (ret) { 116662306a36Sopenharmony_ci dev_err(dev, "could not load firmware\n"); 116762306a36Sopenharmony_ci goto out; 116862306a36Sopenharmony_ci } 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci firmware_loaded = 1; 117162306a36Sopenharmony_ci out: 117262306a36Sopenharmony_ci release_firmware(fw); 117362306a36Sopenharmony_ci} 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_cistatic int soft_uart_init(struct platform_device *ofdev) 117662306a36Sopenharmony_ci{ 117762306a36Sopenharmony_ci struct device_node *np = ofdev->dev.of_node; 117862306a36Sopenharmony_ci struct qe_firmware_info *qe_fw_info; 117962306a36Sopenharmony_ci int ret; 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci if (of_property_read_bool(np, "soft-uart")) { 118262306a36Sopenharmony_ci dev_dbg(&ofdev->dev, "using Soft-UART mode\n"); 118362306a36Sopenharmony_ci soft_uart = 1; 118462306a36Sopenharmony_ci } else { 118562306a36Sopenharmony_ci return 0; 118662306a36Sopenharmony_ci } 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci qe_fw_info = qe_get_firmware_info(); 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci /* Check if the firmware has been uploaded. */ 119162306a36Sopenharmony_ci if (qe_fw_info && strstr(qe_fw_info->id, "Soft-UART")) { 119262306a36Sopenharmony_ci firmware_loaded = 1; 119362306a36Sopenharmony_ci } else { 119462306a36Sopenharmony_ci char filename[32]; 119562306a36Sopenharmony_ci unsigned int soc; 119662306a36Sopenharmony_ci unsigned int rev_h; 119762306a36Sopenharmony_ci unsigned int rev_l; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci soc = soc_info(&rev_h, &rev_l); 120062306a36Sopenharmony_ci if (!soc) { 120162306a36Sopenharmony_ci dev_err(&ofdev->dev, "unknown CPU model\n"); 120262306a36Sopenharmony_ci return -ENXIO; 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci sprintf(filename, "fsl_qe_ucode_uart_%u_%u%u.bin", 120562306a36Sopenharmony_ci soc, rev_h, rev_l); 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci dev_info(&ofdev->dev, "waiting for firmware %s\n", 120862306a36Sopenharmony_ci filename); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci /* 121162306a36Sopenharmony_ci * We call request_firmware_nowait instead of 121262306a36Sopenharmony_ci * request_firmware so that the driver can load and 121362306a36Sopenharmony_ci * initialize the ports without holding up the rest of 121462306a36Sopenharmony_ci * the kernel. If hotplug support is enabled in the 121562306a36Sopenharmony_ci * kernel, then we use it. 121662306a36Sopenharmony_ci */ 121762306a36Sopenharmony_ci ret = request_firmware_nowait(THIS_MODULE, 121862306a36Sopenharmony_ci FW_ACTION_UEVENT, filename, &ofdev->dev, 121962306a36Sopenharmony_ci GFP_KERNEL, &ofdev->dev, uart_firmware_cont); 122062306a36Sopenharmony_ci if (ret) { 122162306a36Sopenharmony_ci dev_err(&ofdev->dev, 122262306a36Sopenharmony_ci "could not load firmware %s\n", 122362306a36Sopenharmony_ci filename); 122462306a36Sopenharmony_ci return ret; 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci return 0; 122862306a36Sopenharmony_ci} 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci#else /* !CONFIG_PPC32 */ 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_cistatic int soft_uart_init(struct platform_device *ofdev) 123362306a36Sopenharmony_ci{ 123462306a36Sopenharmony_ci return 0; 123562306a36Sopenharmony_ci} 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci#endif 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_cistatic int ucc_uart_probe(struct platform_device *ofdev) 124162306a36Sopenharmony_ci{ 124262306a36Sopenharmony_ci struct device_node *np = ofdev->dev.of_node; 124362306a36Sopenharmony_ci const char *sprop; /* String OF properties */ 124462306a36Sopenharmony_ci struct uart_qe_port *qe_port = NULL; 124562306a36Sopenharmony_ci struct resource res; 124662306a36Sopenharmony_ci u32 val; 124762306a36Sopenharmony_ci int ret; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci /* 125062306a36Sopenharmony_ci * Determine if we need Soft-UART mode 125162306a36Sopenharmony_ci */ 125262306a36Sopenharmony_ci ret = soft_uart_init(ofdev); 125362306a36Sopenharmony_ci if (ret) 125462306a36Sopenharmony_ci return ret; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci qe_port = kzalloc(sizeof(struct uart_qe_port), GFP_KERNEL); 125762306a36Sopenharmony_ci if (!qe_port) { 125862306a36Sopenharmony_ci dev_err(&ofdev->dev, "can't allocate QE port structure\n"); 125962306a36Sopenharmony_ci return -ENOMEM; 126062306a36Sopenharmony_ci } 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci /* Search for IRQ and mapbase */ 126362306a36Sopenharmony_ci ret = of_address_to_resource(np, 0, &res); 126462306a36Sopenharmony_ci if (ret) { 126562306a36Sopenharmony_ci dev_err(&ofdev->dev, "missing 'reg' property in device tree\n"); 126662306a36Sopenharmony_ci goto out_free; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci if (!res.start) { 126962306a36Sopenharmony_ci dev_err(&ofdev->dev, "invalid 'reg' property in device tree\n"); 127062306a36Sopenharmony_ci ret = -EINVAL; 127162306a36Sopenharmony_ci goto out_free; 127262306a36Sopenharmony_ci } 127362306a36Sopenharmony_ci qe_port->port.mapbase = res.start; 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci /* Get the UCC number (device ID) */ 127662306a36Sopenharmony_ci /* UCCs are numbered 1-7 */ 127762306a36Sopenharmony_ci if (of_property_read_u32(np, "cell-index", &val)) { 127862306a36Sopenharmony_ci if (of_property_read_u32(np, "device-id", &val)) { 127962306a36Sopenharmony_ci dev_err(&ofdev->dev, "UCC is unspecified in device tree\n"); 128062306a36Sopenharmony_ci ret = -EINVAL; 128162306a36Sopenharmony_ci goto out_free; 128262306a36Sopenharmony_ci } 128362306a36Sopenharmony_ci } 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci if (val < 1 || val > UCC_MAX_NUM) { 128662306a36Sopenharmony_ci dev_err(&ofdev->dev, "no support for UCC%u\n", val); 128762306a36Sopenharmony_ci ret = -ENODEV; 128862306a36Sopenharmony_ci goto out_free; 128962306a36Sopenharmony_ci } 129062306a36Sopenharmony_ci qe_port->ucc_num = val - 1; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci /* 129362306a36Sopenharmony_ci * In the future, we should not require the BRG to be specified in the 129462306a36Sopenharmony_ci * device tree. If no clock-source is specified, then just pick a BRG 129562306a36Sopenharmony_ci * to use. This requires a new QE library function that manages BRG 129662306a36Sopenharmony_ci * assignments. 129762306a36Sopenharmony_ci */ 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci sprop = of_get_property(np, "rx-clock-name", NULL); 130062306a36Sopenharmony_ci if (!sprop) { 130162306a36Sopenharmony_ci dev_err(&ofdev->dev, "missing rx-clock-name in device tree\n"); 130262306a36Sopenharmony_ci ret = -ENODEV; 130362306a36Sopenharmony_ci goto out_free; 130462306a36Sopenharmony_ci } 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci qe_port->us_info.rx_clock = qe_clock_source(sprop); 130762306a36Sopenharmony_ci if ((qe_port->us_info.rx_clock < QE_BRG1) || 130862306a36Sopenharmony_ci (qe_port->us_info.rx_clock > QE_BRG16)) { 130962306a36Sopenharmony_ci dev_err(&ofdev->dev, "rx-clock-name must be a BRG for UART\n"); 131062306a36Sopenharmony_ci ret = -ENODEV; 131162306a36Sopenharmony_ci goto out_free; 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci#ifdef LOOPBACK 131562306a36Sopenharmony_ci /* In internal loopback mode, TX and RX must use the same clock */ 131662306a36Sopenharmony_ci qe_port->us_info.tx_clock = qe_port->us_info.rx_clock; 131762306a36Sopenharmony_ci#else 131862306a36Sopenharmony_ci sprop = of_get_property(np, "tx-clock-name", NULL); 131962306a36Sopenharmony_ci if (!sprop) { 132062306a36Sopenharmony_ci dev_err(&ofdev->dev, "missing tx-clock-name in device tree\n"); 132162306a36Sopenharmony_ci ret = -ENODEV; 132262306a36Sopenharmony_ci goto out_free; 132362306a36Sopenharmony_ci } 132462306a36Sopenharmony_ci qe_port->us_info.tx_clock = qe_clock_source(sprop); 132562306a36Sopenharmony_ci#endif 132662306a36Sopenharmony_ci if ((qe_port->us_info.tx_clock < QE_BRG1) || 132762306a36Sopenharmony_ci (qe_port->us_info.tx_clock > QE_BRG16)) { 132862306a36Sopenharmony_ci dev_err(&ofdev->dev, "tx-clock-name must be a BRG for UART\n"); 132962306a36Sopenharmony_ci ret = -ENODEV; 133062306a36Sopenharmony_ci goto out_free; 133162306a36Sopenharmony_ci } 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci /* Get the port number, numbered 0-3 */ 133462306a36Sopenharmony_ci if (of_property_read_u32(np, "port-number", &val)) { 133562306a36Sopenharmony_ci dev_err(&ofdev->dev, "missing port-number in device tree\n"); 133662306a36Sopenharmony_ci ret = -EINVAL; 133762306a36Sopenharmony_ci goto out_free; 133862306a36Sopenharmony_ci } 133962306a36Sopenharmony_ci qe_port->port.line = val; 134062306a36Sopenharmony_ci if (qe_port->port.line >= UCC_MAX_UART) { 134162306a36Sopenharmony_ci dev_err(&ofdev->dev, "port-number must be 0-%u\n", 134262306a36Sopenharmony_ci UCC_MAX_UART - 1); 134362306a36Sopenharmony_ci ret = -EINVAL; 134462306a36Sopenharmony_ci goto out_free; 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci qe_port->port.irq = irq_of_parse_and_map(np, 0); 134862306a36Sopenharmony_ci if (qe_port->port.irq == 0) { 134962306a36Sopenharmony_ci dev_err(&ofdev->dev, "could not map IRQ for UCC%u\n", 135062306a36Sopenharmony_ci qe_port->ucc_num + 1); 135162306a36Sopenharmony_ci ret = -EINVAL; 135262306a36Sopenharmony_ci goto out_free; 135362306a36Sopenharmony_ci } 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci /* 135662306a36Sopenharmony_ci * Newer device trees have an "fsl,qe" compatible property for the QE 135762306a36Sopenharmony_ci * node, but we still need to support older device trees. 135862306a36Sopenharmony_ci */ 135962306a36Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "fsl,qe"); 136062306a36Sopenharmony_ci if (!np) { 136162306a36Sopenharmony_ci np = of_find_node_by_type(NULL, "qe"); 136262306a36Sopenharmony_ci if (!np) { 136362306a36Sopenharmony_ci dev_err(&ofdev->dev, "could not find 'qe' node\n"); 136462306a36Sopenharmony_ci ret = -EINVAL; 136562306a36Sopenharmony_ci goto out_free; 136662306a36Sopenharmony_ci } 136762306a36Sopenharmony_ci } 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci if (of_property_read_u32(np, "brg-frequency", &val)) { 137062306a36Sopenharmony_ci dev_err(&ofdev->dev, 137162306a36Sopenharmony_ci "missing brg-frequency in device tree\n"); 137262306a36Sopenharmony_ci ret = -EINVAL; 137362306a36Sopenharmony_ci goto out_np; 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci if (val) 137762306a36Sopenharmony_ci qe_port->port.uartclk = val; 137862306a36Sopenharmony_ci else { 137962306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_PPC32)) { 138062306a36Sopenharmony_ci dev_err(&ofdev->dev, 138162306a36Sopenharmony_ci "invalid brg-frequency in device tree\n"); 138262306a36Sopenharmony_ci ret = -EINVAL; 138362306a36Sopenharmony_ci goto out_np; 138462306a36Sopenharmony_ci } 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci /* 138762306a36Sopenharmony_ci * Older versions of U-Boot do not initialize the brg-frequency 138862306a36Sopenharmony_ci * property, so in this case we assume the BRG frequency is 138962306a36Sopenharmony_ci * half the QE bus frequency. 139062306a36Sopenharmony_ci */ 139162306a36Sopenharmony_ci if (of_property_read_u32(np, "bus-frequency", &val)) { 139262306a36Sopenharmony_ci dev_err(&ofdev->dev, 139362306a36Sopenharmony_ci "missing QE bus-frequency in device tree\n"); 139462306a36Sopenharmony_ci ret = -EINVAL; 139562306a36Sopenharmony_ci goto out_np; 139662306a36Sopenharmony_ci } 139762306a36Sopenharmony_ci if (val) 139862306a36Sopenharmony_ci qe_port->port.uartclk = val / 2; 139962306a36Sopenharmony_ci else { 140062306a36Sopenharmony_ci dev_err(&ofdev->dev, 140162306a36Sopenharmony_ci "invalid QE bus-frequency in device tree\n"); 140262306a36Sopenharmony_ci ret = -EINVAL; 140362306a36Sopenharmony_ci goto out_np; 140462306a36Sopenharmony_ci } 140562306a36Sopenharmony_ci } 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci spin_lock_init(&qe_port->port.lock); 140862306a36Sopenharmony_ci qe_port->np = np; 140962306a36Sopenharmony_ci qe_port->port.dev = &ofdev->dev; 141062306a36Sopenharmony_ci qe_port->port.ops = &qe_uart_pops; 141162306a36Sopenharmony_ci qe_port->port.iotype = UPIO_MEM; 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci qe_port->tx_nrfifos = TX_NUM_FIFO; 141462306a36Sopenharmony_ci qe_port->tx_fifosize = TX_BUF_SIZE; 141562306a36Sopenharmony_ci qe_port->rx_nrfifos = RX_NUM_FIFO; 141662306a36Sopenharmony_ci qe_port->rx_fifosize = RX_BUF_SIZE; 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci qe_port->wait_closing = UCC_WAIT_CLOSING; 141962306a36Sopenharmony_ci qe_port->port.fifosize = 512; 142062306a36Sopenharmony_ci qe_port->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci qe_port->us_info.ucc_num = qe_port->ucc_num; 142362306a36Sopenharmony_ci qe_port->us_info.regs = (phys_addr_t) res.start; 142462306a36Sopenharmony_ci qe_port->us_info.irq = qe_port->port.irq; 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci qe_port->us_info.rx_bd_ring_len = qe_port->rx_nrfifos; 142762306a36Sopenharmony_ci qe_port->us_info.tx_bd_ring_len = qe_port->tx_nrfifos; 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci /* Make sure ucc_slow_init() initializes both TX and RX */ 143062306a36Sopenharmony_ci qe_port->us_info.init_tx = 1; 143162306a36Sopenharmony_ci qe_port->us_info.init_rx = 1; 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci /* Add the port to the uart sub-system. This will cause 143462306a36Sopenharmony_ci * qe_uart_config_port() to be called, so the us_info structure must 143562306a36Sopenharmony_ci * be initialized. 143662306a36Sopenharmony_ci */ 143762306a36Sopenharmony_ci ret = uart_add_one_port(&ucc_uart_driver, &qe_port->port); 143862306a36Sopenharmony_ci if (ret) { 143962306a36Sopenharmony_ci dev_err(&ofdev->dev, "could not add /dev/ttyQE%u\n", 144062306a36Sopenharmony_ci qe_port->port.line); 144162306a36Sopenharmony_ci goto out_np; 144262306a36Sopenharmony_ci } 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci platform_set_drvdata(ofdev, qe_port); 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci dev_info(&ofdev->dev, "UCC%u assigned to /dev/ttyQE%u\n", 144762306a36Sopenharmony_ci qe_port->ucc_num + 1, qe_port->port.line); 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci /* Display the mknod command for this device */ 145062306a36Sopenharmony_ci dev_dbg(&ofdev->dev, "mknod command is 'mknod /dev/ttyQE%u c %u %u'\n", 145162306a36Sopenharmony_ci qe_port->port.line, SERIAL_QE_MAJOR, 145262306a36Sopenharmony_ci SERIAL_QE_MINOR + qe_port->port.line); 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci return 0; 145562306a36Sopenharmony_ciout_np: 145662306a36Sopenharmony_ci of_node_put(np); 145762306a36Sopenharmony_ciout_free: 145862306a36Sopenharmony_ci kfree(qe_port); 145962306a36Sopenharmony_ci return ret; 146062306a36Sopenharmony_ci} 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_cistatic int ucc_uart_remove(struct platform_device *ofdev) 146362306a36Sopenharmony_ci{ 146462306a36Sopenharmony_ci struct uart_qe_port *qe_port = platform_get_drvdata(ofdev); 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci dev_info(&ofdev->dev, "removing /dev/ttyQE%u\n", qe_port->port.line); 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci uart_remove_one_port(&ucc_uart_driver, &qe_port->port); 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci of_node_put(qe_port->np); 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci kfree(qe_port); 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci return 0; 147562306a36Sopenharmony_ci} 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_cistatic const struct of_device_id ucc_uart_match[] = { 147862306a36Sopenharmony_ci { 147962306a36Sopenharmony_ci .type = "serial", 148062306a36Sopenharmony_ci .compatible = "ucc_uart", 148162306a36Sopenharmony_ci }, 148262306a36Sopenharmony_ci { 148362306a36Sopenharmony_ci .compatible = "fsl,t1040-ucc-uart", 148462306a36Sopenharmony_ci }, 148562306a36Sopenharmony_ci {}, 148662306a36Sopenharmony_ci}; 148762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ucc_uart_match); 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_cistatic struct platform_driver ucc_uart_of_driver = { 149062306a36Sopenharmony_ci .driver = { 149162306a36Sopenharmony_ci .name = "ucc_uart", 149262306a36Sopenharmony_ci .of_match_table = ucc_uart_match, 149362306a36Sopenharmony_ci }, 149462306a36Sopenharmony_ci .probe = ucc_uart_probe, 149562306a36Sopenharmony_ci .remove = ucc_uart_remove, 149662306a36Sopenharmony_ci}; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_cistatic int __init ucc_uart_init(void) 149962306a36Sopenharmony_ci{ 150062306a36Sopenharmony_ci int ret; 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci printk(KERN_INFO "Freescale QUICC Engine UART device driver\n"); 150362306a36Sopenharmony_ci#ifdef LOOPBACK 150462306a36Sopenharmony_ci printk(KERN_INFO "ucc-uart: Using loopback mode\n"); 150562306a36Sopenharmony_ci#endif 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci ret = uart_register_driver(&ucc_uart_driver); 150862306a36Sopenharmony_ci if (ret) { 150962306a36Sopenharmony_ci printk(KERN_ERR "ucc-uart: could not register UART driver\n"); 151062306a36Sopenharmony_ci return ret; 151162306a36Sopenharmony_ci } 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci ret = platform_driver_register(&ucc_uart_of_driver); 151462306a36Sopenharmony_ci if (ret) { 151562306a36Sopenharmony_ci printk(KERN_ERR 151662306a36Sopenharmony_ci "ucc-uart: could not register platform driver\n"); 151762306a36Sopenharmony_ci uart_unregister_driver(&ucc_uart_driver); 151862306a36Sopenharmony_ci } 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci return ret; 152162306a36Sopenharmony_ci} 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_cistatic void __exit ucc_uart_exit(void) 152462306a36Sopenharmony_ci{ 152562306a36Sopenharmony_ci printk(KERN_INFO 152662306a36Sopenharmony_ci "Freescale QUICC Engine UART device driver unloading\n"); 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci platform_driver_unregister(&ucc_uart_of_driver); 152962306a36Sopenharmony_ci uart_unregister_driver(&ucc_uart_driver); 153062306a36Sopenharmony_ci} 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_cimodule_init(ucc_uart_init); 153362306a36Sopenharmony_cimodule_exit(ucc_uart_exit); 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ciMODULE_DESCRIPTION("Freescale QUICC Engine (QE) UART"); 153662306a36Sopenharmony_ciMODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); 153762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 153862306a36Sopenharmony_ciMODULE_ALIAS_CHARDEV_MAJOR(SERIAL_QE_MAJOR); 153962306a36Sopenharmony_ci 1540