[patch v4 1/5] AST2500 DMA UART driver

Greg KH gregkh at linuxfoundation.org
Wed Jul 31 01:47:59 AEST 2019


On Fri, Jul 26, 2019 at 06:57:16PM +0530, sudheer.v wrote:
> From: sudheer veliseti <sudheer.open at gmail.com>
> 
> UART driver for Aspeed's bmc chip AST2500
> 
> Design approch:
> AST2500 has dedicated Uart DMA controller which has 12 sets of Tx and RX channels
> connected to UART controller directly.
> Since the DMA controller have dedicated buffers and registers,
> there would be little benifit in adding DMA framework overhead.
> So the software for DMA controller is included within the UART driver itself.
> 
> implementation details:
> 'struct ast_uart_port' is populated and registered with uart_core.
> code is organised into two layers UART-layer and DMA-Layer,both of them are
> in the same file.UART-layer requests Rx and Tx dma channels
> and registers callbacks with DMA controller software Layer
> Interrupt service routine for DMA controller is the crucial one for Handling all
> the tx and rx data. ISRs installed for individual uarts are just dummy,and are helpful 
> only to report any spurious interrupts in hardware.
> 
> 
> Signed-off-by: sudheer veliseti <sudheer.open at gmail.com>
> ---
> 
> Changes from v3->v4:
> - per port uart structures are registerd directly with uart core 
>   Instead of registering through 8250 Frame work,
>   ast_uart_port is registered using uart_add_one_port
> -SDMA_RX_FIX macro replaced with CONFIG_AST_UART_DMA_RX_INTERRUPT
> -ast_uart_sdma_isr : DMA interrupt handler code is improvised
> -replaced pr_debug with ftrace wherever appropriate
> -dev_err is used in all error return cases
> -uart driver structure ast25xx_uart_reg is modified
> -driver name changed to ast2500-uart-dma-drv
> -rx_timer initialisation and callback fn modified
> 
> Changes from v2->v3:
> -custom debug replaced by in kerenl dynamic debug: pr_debug 
> -change-logs added 
> 
> 
> .../tty/serial/8250/8250_ast2500_uart_dma.c   | 1901 +++++++++++++++++
>  1 file changed, 1901 insertions(+)
>  create mode 100644 drivers/tty/serial/8250/8250_ast2500_uart_dma.c
> 
> diff --git a/drivers/tty/serial/8250/8250_ast2500_uart_dma.c b/drivers/tty/serial/8250/8250_ast2500_uart_dma.c
> new file mode 100644
> index 000000000000..bc830d605372
> --- /dev/null
> +++ b/drivers/tty/serial/8250/8250_ast2500_uart_dma.c
> @@ -0,0 +1,1901 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + *  DMA UART Driver for ASPEED BMC chip: AST2500
> + *
> + *  Copyright (C) 2019 sudheer Kumar veliseti, Aspeed technology Inc.
> + *  <open.sudheer at gmail.com>

What was the copyright on the file you copied?  Please properly
attribute that here.


> + *
> + */
> +#include <linux/clk.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/tty.h>
> +#include <linux/tty_flip.h>
> +#include "8250.h"
> +
> +#define SERIAL8250_CONSOLE NULL
> +#define TTY_AST_MAJOR 204
> +#define TTY_AST_MINOR 68

Where did you get this minor number from?

> +
> +#define DMA_BUFF_SIZE		0x1000
> +#define SDMA_RX_BUFF_SIZE	0x10000
> +#define PASS_LIMIT 256
> +#define UART_DMA_NR CONFIG_AST_NR_DMA_UARTS
> +#define AST_UART_SDMA_CH 12
> +
> +/* enum ast_uart_chan_op
> + * operation codes passed to the DMA code by the user, and also used
> + * to inform the current channel owner of any changes to the system state
> + */
> +enum ast_uart_chan_op {
> +	AST_UART_DMAOP_TRIGGER,
> +	AST_UART_DMAOP_STOP,
> +	AST_UART_DMAOP_PAUSE,
> +};
> +
> +/* ast_uart_dma_cbfn: buffer callback routinei type */
> +typedef void (*ast_uart_dma_cbfn)(void *dev_id, u16 len);
> +
> +struct ast_sdma_info {
> +	u8 ch_no;
> +	u8 direction;
> +	u8 enable;
> +	void *priv;
> +	char *sdma_virt_addr;
> +	dma_addr_t dma_phy_addr;
> +	/* cdriver callbacks */
> +	ast_uart_dma_cbfn callback_fn; /* buffer done callback */
> +};
> +
> +struct ast_sdma_ch {
> +	struct ast_sdma_info tx_dma_info[AST_UART_SDMA_CH];
> +	struct ast_sdma_info rx_dma_info[AST_UART_SDMA_CH];
> +};
> +
> +struct ast_sdma {
> +	void __iomem *reg_base;
> +	int dma_irq;
> +	struct ast_sdma_ch *dma_ch;
> +	struct regmap *map;
> +};
> +
> +#define UART_TX_SDMA_EN		0x00
> +#define UART_RX_SDMA_EN		0x04
> +#define UART_SDMA_CONF		0x08 /* Misc, Buffer size  */
> +#define UART_SDMA_TIMER		0x0C
> +#define UART_TX_SDMA_REST	0x20
> +#define UART_RX_SDMA_REST	0x24
> +#define UART_TX_SDMA_IER	0x30
> +#define UART_TX_SDMA_ISR	0x34
> +#define UART_RX_SDMA_IER	0x38
> +#define UART_RX_SDMA_ISR	0x3C
> +#define UART_TX_R_POINT(x)	(0x40 + ((x) * 0x20))
> +#define UART_TX_W_POINT(x)	(0x44 + ((x) * 0x20))
> +#define UART_TX_SDMA_ADDR(x)	(0x48 + ((x) * 0x20))
> +#define UART_RX_R_POINT(x)	(0x50 + ((x) * 0x20))
> +#define UART_RX_W_POINT(x)	(0x54 + ((x) * 0x20))
> +#define UART_RX_SDMA_ADDR(x)	(0x58 + ((x) * 0x20))
> +#define SDMA_CH_EN(x)		BIT(x)
> +
> +#define SDMA_TX_BUFF_SIZE_MASK	(0x3)
> +#define SDMA_SET_TX_BUFF_SIZE(x)(x)
> +#define SDMA_BUFF_SIZE_1KB	(0x0)
> +#define SDMA_BUFF_SIZE_4KB	(0x1)
> +#define SDMA_BUFF_SIZE_16KB	(0x2)
> +#define SDMA_BUFF_SIZE_64KB	(0x3)
> +#define SDMA_RX_BUFF_SIZE_MASK	(0x3 << 2)
> +#define SDMA_SET_RX_BUFF_SIZE(x)((x) << 2)
> +#define SDMA_TIMEOUT_DIS	BIT(4)
> +
> +#define UART_SDMA11_INT		BIT(11)
> +#define UART_SDMA10_INT		BIT(10)
> +#define UART_SDMA9_INT		BIT(9)
> +#define UART_SDMA8_INT		BIT(8)
> +#define UART_SDMA7_INT		BIT(7)
> +#define UART_SDMA6_INT		BIT(6)
> +#define UART_SDMA5_INT		BIT(5)
> +#define UART_SDMA4_INT		BIT(4)
> +#define UART_SDMA3_INT		BIT(3)
> +#define UART_SDMA2_INT		BIT(2)
> +#define UART_SDMA1_INT		BIT(1)
> +#define UART_SDMA0_INT		BIT(0)
> +
> +/*
> + * Configuration:
> + *   share_irqs - whether we pass IRQF_SHARED to request_irq().
> + *   This option is unsafe when used on edge-triggered interrupts.
> + */
> +static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
> +
> +static unsigned int nr_uarts = CONFIG_AST_RUNTIME_DMA_UARTS;
> +
> +struct ast_uart_port {
> +	struct uart_port port;
> +	unsigned short capabilities; /* port capabilities */
> +	unsigned short bugs;         /* port bugs */
> +	unsigned int tx_loadsz;      /* transmit fifo load size */
> +	unsigned char acr;
> +	unsigned char ier;
> +	unsigned char lcr;
> +	unsigned char mcr;
> +	unsigned char mcr_mask;  /* mask of user bits */
> +	unsigned char mcr_force; /* mask of forced bits */
> +	struct circ_buf rx_dma_buf;
> +	struct circ_buf tx_dma_buf;
> +	unsigned char dma_channel;
> +	dma_addr_t dma_rx_addr; /* Mapped ADMA descr. table */
> +	dma_addr_t dma_tx_addr; /* Mapped ADMA descr. table */
> +#ifdef CONFIG_AST_UART_DMA_RX_INTERRUPT
> +	struct tasklet_struct rx_tasklet;
> +#else
> +	struct timer_list rx_timer;
> +	unsigned int workaround;
> +#endif
> +	struct tasklet_struct tx_tasklet;
> +	spinlock_t lock;
> +	int tx_done;
> +	int tx_count;
> +	struct platform_device *ast_uart_pdev;
> +/*
> + * Some bits in registers are cleared on a read, so they must
> + * be saved whenever the register is read but the bits will not
> + * be immediately processed.
> + */
> +#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
> +	unsigned char lsr_saved_flags;
> +#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
> +	unsigned char msr_saved_flags;
> +
> +	/*
> +	 * We provide a per-port pm hook.
> +	 */
> +	void (*pm)(struct uart_port *port, unsigned int state,
> +						 unsigned int old);
> +};
> +
> +static struct ast_uart_port ast_uart_ports[UART_DMA_NR];
> +
> +#define GET_DEV(ast_uart_port_priv_ptr)\
> +		(ast_uart_port_priv_ptr->ast_uart_pdev->dev)
> +
> +static inline struct ast_uart_port *
> +to_ast_dma_uart_port(struct uart_port *uart) {
> +	return container_of(uart, struct ast_uart_port, port);
> +}
> +
> +struct irq_info {
> +	spinlock_t lock;
> +	struct ast_uart_port *up;
> +};
> +
> +static struct irq_info ast_uart_irq[1];
> +static DEFINE_MUTEX(ast_uart_mutex);
> +
> +/*
> + * Here we define the default xmit fifo size used for each type of UART.
> + */
> +static const struct serial8250_config uart_config[] = {
> +	[PORT_UNKNOWN] = {
> +		.name		= "unknown",
> +		.fifo_size	= 1,
> +		.tx_loadsz	= 1,
> +	},
> +	[PORT_8250] = {
> +		.name		= "8250",
> +		.fifo_size	= 1,
> +		.tx_loadsz	= 1,
> +	},
> +	[PORT_16450] = {
> +		.name		= "16450",
> +		.fifo_size	= 1,
> +		.tx_loadsz	= 1,
> +	},
> +	[PORT_16550] = {
> +		.name		= "16550",
> +		.fifo_size	= 1,
> +		.tx_loadsz	= 1,
> +	},
> +	[PORT_16550A] = {
> +		.name		= "16550A",
> +		.fifo_size	= 16,
> +		.tx_loadsz	= 16,
> +		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10
> +							| UART_FCR_DMA_SELECT,
> +		.flags		= UART_CAP_FIFO,
> +	},
> +};

I doubt you need all of these port types, right?  You only have one type
of device, please strip out _ALL_ of the unneeded code in here.  You did
a wholesale copy of the old driver, to get away with that you then need
to customize it to work properly with your hardware _AND_ take away all
code that is not needed for your hardware.

Lots of this file can be removed, please do so.

thanks,

greg k-h


More information about the Linux-aspeed mailing list