/* * 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 */#defineDW_REG_THR 0
#defineDW_REG_RBR 0
#defineDW_REG_BRDL 0
#defineDW_REG_BRDH 4
#defineDW_REG_FCR 8
#defineDW_REG_LCR 12
#defineDW_REG_LSR 20
#defineuart_read(dev, reg)\
io_reg_read(dev->port + reg)
#defineuart_write(dev, reg, value)\
io_reg_write(dev->port + reg, value)
/* lcr register *//* * 0x0 -- 5bits * 0x1 -- 6bits * 0x2 -- 7bits * 0x3 -- 8bits */#defineLCR_DLS(x) (x << 0)
/* 0-1stop, 1-1.5stop */#defineLCR_STOP(x) (x << 2)
/* 0-parity disabled, 1-parity enabled */#defineLCR_PEN(x) (x << 3)
#defineLCR_DLAB_BIT (1 << 7)
/* fcr register *//* 0-fifo disabled; 1-enabled */#defineFCR_FIFOE(x) (x << 0)
/* 0-mode0, 1-mode1 */#defineFCR_MODE(x) (x << 3)
#defineFCR_RCVR_RST (1 << 1
#defineFCR_XMIT_RST (1 << 2)
/* lsr register */#defineLSR_TEMT (1 << 2) /* transmitter empty *//* TODO: this goes in sof/uart.h */structuart*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;
intrx_buffer_size;
inttx_buffer_size;
void*private;
structuart_pdata*pdata;
};
/* TODO: this goes in platform/uart.c */staticstructuart_pdatadw_pdata= {
.baud=1152000, /* Baud rate */
.port=DW_REG_BASEADDR,
.timeout=DW_TIMEOUT,
};
/* All Tx/Rx is done by IRQ handler */staticintdw_uart_irq(void*data)
{
structuart*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 */
}
staticintdw_uart_write_data(structuart*uart, char*data, intlen)
{
/* TODO copy data to Tx circular buffer */
}
staticintdw_uart_read_data(structuart*uart, char*data, intlen)
{
/* TODO copy data from Rx circular buffer */
}
staticintdw_uart_probe(structuart*uart)
{
structuart_pdata*pdata=uart->pdata;
uint32_tdivisor, 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);
return0;
}
conststructuart_opsdw_uart_ops= {
.set_config=dw_uart_set_config,
.probe=dw_uart_probe,
.tx_data=dw_uart_write_data,
.rx_data=dw_uart_read_data, };
@zhigang-wu please use this as starting point for UART, it must not block and should use IRQ for Tx/Rx data.