288 lines
8.4 KiB
C
288 lines
8.4 KiB
C
|
/*
|
|||
|
* Copyright : (C) 2022 Phytium Information Technology, Inc.
|
|||
|
* All Rights Reserved.
|
|||
|
*
|
|||
|
* This program is OPEN SOURCE software: you can redistribute it and/or modify it
|
|||
|
* under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
|
|||
|
* either version 1.0 of the License, or (at your option) any later version.
|
|||
|
*
|
|||
|
* This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
|
|||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|||
|
* See the Phytium Public License for more details.
|
|||
|
*
|
|||
|
*
|
|||
|
* FilePath: fpl011.c
|
|||
|
* Date: 2022-02-10 14:53:42
|
|||
|
* LastEditTime: 2022-02-18 09:07:24
|
|||
|
* Description: This files is for uart functions
|
|||
|
*
|
|||
|
* Modify History:
|
|||
|
* Ver Who Date Changes
|
|||
|
* ----- ------ -------- --------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
/***************************** Include Files ********************************/
|
|||
|
|
|||
|
#include "fpl011.h"
|
|||
|
#include "fio.h"
|
|||
|
#include "ferror_code.h"
|
|||
|
|
|||
|
/************************** Constant Definitions *****************************/
|
|||
|
|
|||
|
/**************************** Type Definitions *******************************/
|
|||
|
|
|||
|
/***************** Macros (Inline Functions) Definitions *********************/
|
|||
|
|
|||
|
/************************** Function Prototypes ******************************/
|
|||
|
|
|||
|
u32 FPl011SendBuffer(FPl011 *uart_p);
|
|||
|
u32 FPl011ReceiveBuffer(FPl011 *uart_p);
|
|||
|
|
|||
|
static void FPl011StubHandler(void *Args, u32 Event,
|
|||
|
u32 ByteCount);
|
|||
|
/*****************************************************************************/
|
|||
|
|
|||
|
|
|||
|
FError FPl011CfgInitialize(FPl011 *uart_p, FPl011Config *config)
|
|||
|
{
|
|||
|
u32 reg_value = 0;
|
|||
|
FError ret ;
|
|||
|
FASSERT(uart_p != NULL);
|
|||
|
FASSERT(config != NULL);
|
|||
|
|
|||
|
uart_p->config.instance_id = config->instance_id;
|
|||
|
uart_p->config.base_address = config->base_address;
|
|||
|
uart_p->config.ref_clock_hz = config->ref_clock_hz;
|
|||
|
uart_p->config.irq_num = config->irq_num;
|
|||
|
uart_p->config.baudrate = config->baudrate;
|
|||
|
|
|||
|
uart_p->handler = FPl011StubHandler;
|
|||
|
|
|||
|
uart_p->send_buffer.byte_p = NULL;
|
|||
|
uart_p->send_buffer.requested_bytes = 0;
|
|||
|
uart_p->send_buffer.remaining_bytes = 0;
|
|||
|
|
|||
|
uart_p->receive_buffer.byte_p = NULL;
|
|||
|
uart_p->receive_buffer.requested_bytes = 0;
|
|||
|
uart_p->receive_buffer.remaining_bytes = 0;
|
|||
|
uart_p->rxbs_error = 0;
|
|||
|
|
|||
|
uart_p->is_ready = FT_COMPONENT_IS_READY;
|
|||
|
ret = FPl011SetBaudRate(uart_p, uart_p->config.baudrate);
|
|||
|
if (ret != FT_SUCCESS)
|
|||
|
{
|
|||
|
uart_p->is_ready = 0U;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/*
|
|||
|
* Set up the default data format: 8 bit data, 1 stop bit, no
|
|||
|
* parity
|
|||
|
*/
|
|||
|
reg_value = ((FPL011_FORMAT_WORDLENGTH_8BIT << 5) & FPL011LCR_H_WLEN); //<! 8bit word length
|
|||
|
reg_value |= (0 << 3) & FPL011LCR_H_STP2; //<! 1 stopbit
|
|||
|
reg_value |= (0 << 1) & FPL011LCR_H_PEN; //<! no parity
|
|||
|
reg_value |= (1 << 4) & FPL011LCR_H_FEN; //<! fifo en
|
|||
|
FUART_WRITEREG32(uart_p->config.base_address, FPL011LCR_H_OFFSET, reg_value);
|
|||
|
|
|||
|
/* Set the RX FIFO trigger at 8 data bytes.Tx FIFO trigger is 8 data bytes*/
|
|||
|
reg_value = (1 << 3) | (1 << 0);
|
|||
|
FUART_WRITEREG32(uart_p->config.base_address, FPL011IFLS_OFFSET, reg_value);
|
|||
|
|
|||
|
/* Disable all interrupts, polled mode is the default */
|
|||
|
reg_value = 0;
|
|||
|
FUART_WRITEREG32(uart_p->config.base_address, FPL011IMSC_OFFSET, reg_value);
|
|||
|
}
|
|||
|
|
|||
|
return FT_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* @name: FPl011Send
|
|||
|
* @msg: This functions sends the specified buffer using the device in either
|
|||
|
* polled or interrupt driven mode.
|
|||
|
* @return The number of bytes actually sent.
|
|||
|
* @param uart_p is a pointer to the FPl011 instance.
|
|||
|
* @param byte_p is pointer to a buffer of data to be sent.
|
|||
|
* @param length ontains the number of bytes to be sent. Any data that was already put into the
|
|||
|
* transmit FIFO will be sent.
|
|||
|
*/
|
|||
|
u32 FPl011Send(FPl011 *uart_p, u8 *byte_p, u32 length)
|
|||
|
{
|
|||
|
u32 sent_count = 0;
|
|||
|
FASSERT(uart_p != NULL);
|
|||
|
FASSERT(byte_p != NULL);
|
|||
|
FASSERT(uart_p->is_ready == FT_COMPONENT_IS_READY);
|
|||
|
|
|||
|
uart_p->send_buffer.byte_p = byte_p;
|
|||
|
uart_p->send_buffer.requested_bytes = length;
|
|||
|
uart_p->send_buffer.remaining_bytes = length;
|
|||
|
sent_count = FPl011SendBuffer(uart_p);
|
|||
|
return sent_count;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
static void FPl011StubHandler(void *args, u32 event,
|
|||
|
u32 byte_count)
|
|||
|
{
|
|||
|
(void)args;
|
|||
|
(void)event;
|
|||
|
(void)byte_count;
|
|||
|
|
|||
|
FASSERT(0);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @name: FPl011SendBuffer
|
|||
|
* @msg: send data buffer through uart
|
|||
|
* @return {*}
|
|||
|
* @param uart_p
|
|||
|
*/
|
|||
|
u32 FPl011SendBuffer(FPl011 *uart_p)
|
|||
|
{
|
|||
|
u32 sent_count = 0U;
|
|||
|
u32 isbusy;
|
|||
|
|
|||
|
isbusy = (u32)FUART_ISTRANSMITBUSY(uart_p->config.base_address);
|
|||
|
while (isbusy == TRUE)
|
|||
|
{
|
|||
|
isbusy = (u32)FUART_ISTRANSMITBUSY(uart_p->config.base_address);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* If the TX FIFO is full, send nothing.
|
|||
|
* Otherwise put bytes into the TX FIFO unil it is full, or all of the
|
|||
|
* data has been put into the FIFO.
|
|||
|
*/
|
|||
|
while ((!FUART_ISTRANSMITFULL(uart_p->config.base_address)) && (uart_p->send_buffer.remaining_bytes > sent_count))
|
|||
|
{
|
|||
|
FUART_WRITEREG32(uart_p->config.base_address, FPL011DR_OFFSET, (u32)uart_p->send_buffer.byte_p[sent_count]);
|
|||
|
sent_count++;
|
|||
|
}
|
|||
|
/* Update the buffer to reflect the bytes that were sent from it */
|
|||
|
uart_p->send_buffer.byte_p += sent_count;
|
|||
|
uart_p->send_buffer.remaining_bytes -= sent_count;
|
|||
|
|
|||
|
return sent_count;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @name: FPl011Receive
|
|||
|
* @msg: This function attempts to receive a specified number of bytes of data
|
|||
|
* from the device and store it into the specified buffer.
|
|||
|
* @param uart_p is a pointer to the FPl011 instance
|
|||
|
* @param byte_p is pointer to buffer for data to be received into
|
|||
|
* @param length is the number of bytes to be received.
|
|||
|
* @return The number of bytes received.
|
|||
|
*/
|
|||
|
u32 FPl011Receive(FPl011 *uart_p, u8 *byte_p, u32 length)
|
|||
|
{
|
|||
|
u32 received;
|
|||
|
|
|||
|
FASSERT(uart_p != NULL);
|
|||
|
FASSERT(byte_p != NULL);
|
|||
|
FASSERT(uart_p->is_ready == FT_COMPONENT_IS_READY);
|
|||
|
|
|||
|
uart_p->receive_buffer.byte_p = byte_p;
|
|||
|
uart_p->receive_buffer.requested_bytes = length;
|
|||
|
uart_p->receive_buffer.remaining_bytes = length;
|
|||
|
|
|||
|
received = FPl011ReceiveBuffer(uart_p);
|
|||
|
|
|||
|
return received;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
u32 FPl011ReceiveBuffer(FPl011 *uart_p)
|
|||
|
{
|
|||
|
|
|||
|
u32 received_count = 0U;
|
|||
|
u32 event;
|
|||
|
u32 event_data;
|
|||
|
u32 byte_value;
|
|||
|
|
|||
|
while ((received_count < uart_p->receive_buffer.remaining_bytes) && !FUART_ISRECEIVEDATA(uart_p->config.base_address))
|
|||
|
{
|
|||
|
byte_value = FUART_READREG32(uart_p->config.base_address, FPL011DR_OFFSET);
|
|||
|
|
|||
|
if (uart_p->rxbs_error)
|
|||
|
{
|
|||
|
if ((byte_value & FPL011DR_ALLE) != 0)
|
|||
|
{
|
|||
|
event_data = byte_value;
|
|||
|
event = FPL011_EVENT_PARE_FRAME_BRKE;
|
|||
|
|
|||
|
if (uart_p->handler)
|
|||
|
{
|
|||
|
uart_p->handler(uart_p->args, event, event_data);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
uart_p->receive_buffer.byte_p[received_count] = (u8)(byte_value & 0xff);
|
|||
|
received_count++;
|
|||
|
}
|
|||
|
|
|||
|
uart_p->rxbs_error = 0;
|
|||
|
|
|||
|
if (uart_p->receive_buffer.byte_p != NULL)
|
|||
|
{
|
|||
|
uart_p->receive_buffer.byte_p += received_count;
|
|||
|
}
|
|||
|
uart_p->receive_buffer.remaining_bytes -= received_count;
|
|||
|
|
|||
|
return received_count;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @name: FPl011BlockSend
|
|||
|
* @msg: initiate uart block send
|
|||
|
* @return {*}
|
|||
|
* @param uart_p
|
|||
|
* @param byte_p
|
|||
|
* @param length
|
|||
|
*/
|
|||
|
void FPl011BlockSend(FPl011 *uart_p, u8 *byte_p, u32 length)
|
|||
|
{
|
|||
|
u32 index;
|
|||
|
|
|||
|
FASSERT(uart_p != NULL);
|
|||
|
FASSERT(byte_p != NULL);
|
|||
|
FASSERT(uart_p->is_ready == FT_COMPONENT_IS_READY);
|
|||
|
|
|||
|
for (index = 0; index < length; index++)
|
|||
|
{
|
|||
|
FPl011SendByte(uart_p->config.base_address, byte_p[index]);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @name: FPl011BlockReceive
|
|||
|
* @msg: initiate uart block receive
|
|||
|
* @return {*}
|
|||
|
* @param uart_p
|
|||
|
*/
|
|||
|
u8 FPl011BlockReceive(FPl011 *uart_p)
|
|||
|
{
|
|||
|
FASSERT(uart_p != NULL);
|
|||
|
FASSERT(uart_p->is_ready == FT_COMPONENT_IS_READY);
|
|||
|
return FPl011RecvByte(uart_p->config.base_address);
|
|||
|
}
|
|||
|
|
|||
|
void FPl011IrqClearReciveTimeOut(FPl011 *uart_p)
|
|||
|
{
|
|||
|
u32 reg_temp;
|
|||
|
reg_temp = FPl011GetInterruptMask(uart_p);
|
|||
|
reg_temp &= ~FPL011MIS_RTMIS;
|
|||
|
FPl011SetInterruptMask(uart_p, reg_temp);
|
|||
|
}
|
|||
|
|
|||
|
void FPl011IrqEnableReciveTimeOut(FPl011 *uart_p)
|
|||
|
{
|
|||
|
u32 reg_temp;
|
|||
|
reg_temp = FPl011GetInterruptMask(uart_p);
|
|||
|
reg_temp |= FPL011MIS_RTMIS;
|
|||
|
FPl011SetInterruptMask(uart_p, reg_temp);
|
|||
|
}
|