Skip to content

UART driver for Sue Creek #384

Description

@lgirdwood

@zhigang-wu please use this as starting point for UART, it must not block and should use IRQ for Tx/Rx data.

/*
 * Copyright (c) 2017, Intel Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   * Neither the name of the Intel Corporation nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Author: Zhigang Wu <zhigang.wu@intel.com>
 */

#include <errno.h>
#include <reef/io.h>
#include <reef/dw-uart.h>

/* uart register list */
#define DW_REG_THR	0
#define DW_REG_RBR	0
#define DW_REG_BRDL	0
#define DW_REG_BRDH	4
#define DW_REG_FCR	8
#define DW_REG_LCR	12
#define DW_REG_LSR	20


#define uart_read(dev, reg)\
	io_reg_read(dev->port + reg)
#define uart_write(dev, reg, value)\
	io_reg_write(dev->port + reg, value)



/* lcr register */
/*
 *	0x0 -- 5bits
 *	0x1 -- 6bits
 *	0x2 -- 7bits
 *	0x3 -- 8bits
 */
#define LCR_DLS(x)	(x << 0)

/* 0-1stop, 1-1.5stop */
#define LCR_STOP(x)	(x << 2)

/* 0-parity disabled, 1-parity enabled */
#define LCR_PEN(x)	(x << 3)

#define LCR_DLAB_BIT	(1 << 7)


/* fcr register */
/* 0-fifo disabled; 1-enabled */
#define FCR_FIFOE(x)	(x << 0)
/* 0-mode0, 1-mode1 */
#define FCR_MODE(x)		(x << 3)
#define FCR_RCVR_RST	(1 << 1
#define FCR_XMIT_RST	(1 << 2)

/* lsr register */
#define LSR_TEMT	(1 << 2)	/* transmitter empty */


/* TODO: this goes in sof/uart.h */
struct uart *uart {
	char *tx_buffer;
	char *rx_buffer;
	char *tx_read_ptr;	/* read this char into HW */
	char *tx_write_ptr;	/* write this char into circular buffer */
	char *rx_read_ptr;
	char *rx_write_ptr;
	int rx_buffer_size;
	int tx_buffer_size;
	void *private;
	struct uart_pdata *pdata;
};

/* TODO: this goes in platform/uart.c */
static struct uart_pdata dw_pdata = {
	.baud = 1152000,	/* Baud rate */
	.port = DW_REG_BASEADDR,
	.timeout = DW_TIMEOUT,
};

/* All Tx/Rx is done by IRQ handler */
static int dw_uart_irq(void *data)
{
	struct uart *uart = data;

	/* TODO check we have new data to send */
	
	/* check Tx is ready for next char */
	if (uart_read(dev, DW_REG_LSR) & LSR_TEMT) {

		/* write to output reg */
		uart_write(dev, DW_REG_THR, uart->tx_read_ptr);

		/* update tx read ptr and check for wrap */
		uart->tx_read_ptr++;
		if (uart->tx_read_ptr >= uart->rx_buffer + uart->rx_buffer_size)
			uart->tx_read_ptr = uart->rx_buffer;
	}

	/* TODO check Rx HW for new data */

}

static int dw_uart_write_data(struct uart *uart, char *data, int len)
{
	/* TODO copy data to Tx circular buffer */
}

static int dw_uart_read_data(struct uart *uart, char *data, int len)
{
	/* TODO copy data from Rx circular buffer */
}

static int dw_uart_probe(struct uart *uart)
{
	struct uart_pdata *pdata = uart->pdata;
	uint32_t divisor, tmp;

	/* TODO: register IRQ handler for Tx/Rx UART FIFO updates.*/

	if (uart->baud != 0) {
		divisor = (SUE_SYS_CLK_FREQ / baud) >> 4;

		/* configure the baudrate */
		tmp = uart_read(dev, DW_REG_LCR);
		uart_write(dev, DW_REG_LCR, LCR_DLAB_BIT);
		uart_write(dev, DW_REG_BRDL,
					(uint8_t)(divisor & 0xFF));
		uart_write(dev, DW_REG_BRDH,
					(uint8_t)((divisor >> 8) & 0xFF));

		/* restore to access baudrate divisor registers */
		uart_write(dev, DW_REG_LCR, tmp);
	}

	/* TODO read this from pdata, i.e. stop bits, parity etc */
	/* 8Bit-data, 1-stop bit, no parity, clear DLAB */
	uart_write(dev, DW_REG_LCR,
		LCR_DLS(3) | LCR_STOP(0) | LCR_PEN(0));

	/* FIFO enalbe, mode0, Tx/Rx FIFO reset */
	uart_write(dev, DW_REG_FCR,
		FCR_FIFOE(1) | FCR_MODE(0) | FCR_RCVR_RST | FCR_XMIT_RST);

	/* reset port */
	uart_write(dev, DW_REG_RBR, 0);

	return 0;
}

const struct uart_ops dw_uart_ops = {
	.set_config	= dw_uart_set_config,
	.probe		= dw_uart_probe,
	.tx_data	= dw_uart_write_data,
	.rx_data	= dw_uart_read_data,	
};

Metadata

Metadata

Assignees

Labels

P2Critical bugs or normal featuresenhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions