Import Mbed OS hard-float snapshot
This commit is contained in:
329
targets/TARGET_Samsung/TARGET_SIDK_S5JS100/serial_pl011_api.c
Normal file
329
targets/TARGET_Samsung/TARGET_SIDK_S5JS100/serial_pl011_api.c
Normal file
@@ -0,0 +1,329 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright 2020 Samsung Electronics All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if DEVICE_SERIAL
|
||||
|
||||
// math.h required for floating point operations for baud rate calculation
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "device.h"
|
||||
#include "serial_api.h"
|
||||
#include "cmsis.h"
|
||||
#include "pinmap.h"
|
||||
#include "PinNames.h"
|
||||
#include "mbed_error.h"
|
||||
#include "mbed_assert.h"
|
||||
#include "gpio_api.h"
|
||||
|
||||
#define UART_PTR(ptr) ((S5JS100_UART_TypeDef *)(ptr))
|
||||
static uart_irq_handler irq_handler[PL011_UART_MAX];
|
||||
|
||||
struct serial_context_data_s {
|
||||
uint32_t serial_irq_id;
|
||||
gpio_t sw_rts, sw_cts;
|
||||
uint8_t count, rx_irq_set_flow, rx_irq_set_api;
|
||||
};
|
||||
|
||||
static struct serial_context_data_s uart_data[PL011_UART_MAX];
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* INTERRUPTS HANDLING
|
||||
******************************************************************************/
|
||||
static inline void uart_irq(t_pl011_ports_enum index,
|
||||
UARTName uart)
|
||||
{
|
||||
S5JS100_UART_TypeDef *p_PL011_UART = UART_PTR(uart);
|
||||
int irq_type = 0xFFFF; /* type none */
|
||||
|
||||
if (!(p_PL011_UART->FR & 1u << 5)) {
|
||||
if (p_PL011_UART->IMSC & 1u << 5) {
|
||||
irq_type = TxIrq;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_PL011_UART->MIS & (1u << 4) || p_PL011_UART->MIS & (1u << 6)) {
|
||||
/*
|
||||
Rx Interrupt & Rx Timeout Interrupt
|
||||
The receive timeout interrupt is asserted when the receive FIFO is not empty,
|
||||
and no further data is received over a 32-bit period.
|
||||
*/
|
||||
irq_type = RxIrq;
|
||||
}
|
||||
|
||||
if (irq_type == RxIrq) {
|
||||
if (uart_data[index].rx_irq_set_api) {
|
||||
(irq_handler[index])(uart_data[index].serial_irq_id, irq_type);
|
||||
}
|
||||
}
|
||||
|
||||
if (irq_type == TxIrq) {
|
||||
/* Clear the TX interrupt Flag */
|
||||
/* UART TX */
|
||||
} else {
|
||||
/* Clear the Rx interupt Flag */
|
||||
/* UART RX */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void uart2_irq()
|
||||
{
|
||||
uart_irq(PL011_UART0_ID, UART_2);
|
||||
}
|
||||
|
||||
static void uart3_irq()
|
||||
{
|
||||
uart_irq(PL011_UART1_ID, UART_3);
|
||||
}
|
||||
|
||||
|
||||
static void pl011_serial_irq_set_internal(void *obj, SerialIrq irq, uint32_t enable)
|
||||
{
|
||||
struct serial_s *priv = (struct serial_s *)obj;
|
||||
S5JS100_UART_TypeDef *p_PL011_UART = UART_PTR(priv->uart);
|
||||
|
||||
|
||||
|
||||
if (enable) {
|
||||
p_PL011_UART->IMSC = 0x50; //interrupt by Rx Timeout & Rx (for fifo mode)
|
||||
|
||||
} else if ((irq == TxIrq) || (uart_data[priv->index].rx_irq_set_api
|
||||
+ uart_data[priv->index].rx_irq_set_flow == 0)) {
|
||||
p_PL011_UART->IMSC = 0; //interrupt by Rx Timeout & Rx (for fifo mode)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// serial_baud
|
||||
// set the baud rate, taking in to account the current SystemFrequency
|
||||
static void pl011_serial_baud(void *obj, int baudrate)
|
||||
{
|
||||
struct serial_s *priv = (struct serial_s *)obj;
|
||||
S5JS100_UART_TypeDef *p_PL011_UART = UART_PTR(priv->uart);
|
||||
|
||||
uint32_t sclk = 0;
|
||||
float div, frac;
|
||||
switch (priv->index) {
|
||||
case PL011_UART0_ID:
|
||||
sclk = cal_clk_getrate(d1_uart0);
|
||||
break;
|
||||
|
||||
case PL011_UART1_ID:
|
||||
sclk = cal_clk_getrate(d1_uart1);
|
||||
break;
|
||||
|
||||
default:
|
||||
MBED_ASSERT(false);
|
||||
}
|
||||
|
||||
div = ((float)sclk / (float)(baudrate * 16));
|
||||
frac = (uint32_t)(((div - (int32_t)div) * 64));
|
||||
|
||||
p_PL011_UART->IBRD = (uint32_t)div;
|
||||
p_PL011_UART->FBRD = (uint32_t)frac;
|
||||
}
|
||||
|
||||
static void pl011_serial_format(void *obj, int data_bits,
|
||||
SerialParity parity, int stop_bits)
|
||||
{
|
||||
struct serial_s *priv = (struct serial_s *)obj;
|
||||
S5JS100_UART_TypeDef *p_PL011_UART = UART_PTR(priv->uart);
|
||||
uint32_t reg;
|
||||
|
||||
switch (data_bits) {
|
||||
case 5:
|
||||
reg = 0;
|
||||
break;
|
||||
case 6:
|
||||
reg = 1 << 5;
|
||||
break;
|
||||
case 7:
|
||||
reg = 2 << 5;
|
||||
break;
|
||||
default:
|
||||
reg = 3 << 5;
|
||||
}
|
||||
|
||||
switch (parity) {
|
||||
case ParityNone:
|
||||
reg |= 0;
|
||||
break;
|
||||
case ParityOdd:
|
||||
reg |= 4;
|
||||
break;
|
||||
case ParityEven:
|
||||
reg |= 6;
|
||||
break;
|
||||
case ParityForced1:
|
||||
reg |= 5;
|
||||
break;
|
||||
case ParityForced0:
|
||||
reg |= 7;
|
||||
break;
|
||||
}
|
||||
|
||||
if (stop_bits == 2) {
|
||||
reg |= 1 << 3;
|
||||
}
|
||||
|
||||
|
||||
/* Enable FIFO */
|
||||
reg |= 1 << 4;
|
||||
|
||||
|
||||
p_PL011_UART->LCRH = reg;
|
||||
}
|
||||
|
||||
static void pl011_serial_irq_handler(void *obj, uart_irq_handler handler, uint32_t id)
|
||||
{
|
||||
struct serial_s *priv = (struct serial_s *)obj;
|
||||
|
||||
irq_handler[priv->index] = handler;
|
||||
uart_data[priv->index].serial_irq_id = id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static void pl011_serial_irq_set(void *obj, SerialIrq irq, uint32_t enable)
|
||||
{
|
||||
struct serial_s *priv = (struct serial_s *)obj;
|
||||
|
||||
if (RxIrq == irq) {
|
||||
uart_data[priv->index].rx_irq_set_api = enable;
|
||||
}
|
||||
|
||||
pl011_serial_irq_set_internal(obj, irq, enable);
|
||||
}
|
||||
|
||||
|
||||
static int pl011_serial_readable(void *obj)
|
||||
{
|
||||
struct serial_s *priv = (struct serial_s *)obj;
|
||||
S5JS100_UART_TypeDef *p_PL011_UART = UART_PTR(priv->uart);
|
||||
return !(p_PL011_UART->FR & (1u << 4));
|
||||
}
|
||||
|
||||
static int pl011_serial_writable(void *obj)
|
||||
{
|
||||
struct serial_s *priv = (struct serial_s *)obj;
|
||||
S5JS100_UART_TypeDef *p_PL011_UART = UART_PTR(priv->uart);
|
||||
return !(p_PL011_UART->FR & (1u << 5));
|
||||
}
|
||||
|
||||
|
||||
static int pl011_serial_getc(void *obj)
|
||||
|
||||
{
|
||||
struct serial_s *priv = (struct serial_s *)obj;
|
||||
S5JS100_UART_TypeDef *p_PL011_UART = UART_PTR(priv->uart);
|
||||
int data;
|
||||
while (!serial_readable(priv));
|
||||
data = p_PL011_UART->DR & 0xFF;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static void pl011_serial_putc(void *obj, int c)
|
||||
{
|
||||
struct serial_s *priv = (struct serial_s *)obj;
|
||||
S5JS100_UART_TypeDef *p_PL011_UART = UART_PTR(priv->uart);
|
||||
|
||||
while (!serial_writable(priv));
|
||||
p_PL011_UART->DR = c;
|
||||
}
|
||||
|
||||
#if DEVICE_SERIAL_FC
|
||||
static void pl011_serial_set_flow_control(struct serial_s *obj, FlowControl type,
|
||||
PinName rxflow, PinName txflow)
|
||||
{
|
||||
error("pl011 flow control is not implenemted");
|
||||
}
|
||||
#endif
|
||||
|
||||
void pl011_serial_init(void *obj, PinName tx, PinName rx)
|
||||
{
|
||||
struct serial_s *priv = (struct serial_s *)obj;
|
||||
S5JS100_UART_TypeDef *p_PL011_UART = UART_PTR(priv->uart);
|
||||
|
||||
/* Declare a variable of type IRQn, initialise to 0 */
|
||||
IRQn_Type irq_n = (IRQn_Type)0;
|
||||
uint32_t vector = 0;
|
||||
|
||||
switch ((int)priv->uart) {
|
||||
case UART_2:
|
||||
irq_n = S5JS100_IRQ_UART0;
|
||||
vector = (uint32_t)&uart2_irq;
|
||||
priv->index = PL011_UART0_ID;
|
||||
break;
|
||||
case UART_3 :
|
||||
irq_n = S5JS100_IRQ_UART1;
|
||||
vector = (uint32_t)&uart3_irq;
|
||||
priv->index = PL011_UART1_ID;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* Enable UART and RX/TX path*/
|
||||
p_PL011_UART->CR = 0x301;
|
||||
/* RX/TX fifo half full interrupt*/
|
||||
p_PL011_UART->IFLS = (2 << 3) | 2;
|
||||
/* clear all interrupts mask */
|
||||
p_PL011_UART->IMSC = 0x0;
|
||||
/* Clear all interripts */
|
||||
p_PL011_UART->ICR = 0x7FF;
|
||||
/* MODESEL as default UART*/
|
||||
p_PL011_UART->MODESEL = 0x0;
|
||||
|
||||
priv->ops.serial_baud = pl011_serial_baud;
|
||||
priv->ops.serial_format = pl011_serial_format;
|
||||
priv->ops.serial_irq_handler = pl011_serial_irq_handler;
|
||||
priv->ops.serial_irq_set = pl011_serial_irq_set;
|
||||
priv->ops.serial_putc = pl011_serial_putc;
|
||||
priv->ops.serial_writable = pl011_serial_writable;
|
||||
priv->ops.serial_getc = pl011_serial_getc;
|
||||
priv->ops.serial_readable = pl011_serial_readable;
|
||||
#if DEVICE_SERIAL_FC
|
||||
priv->ops.serial_set_flow_control = pl011_serial_set_flow_control;
|
||||
#endif
|
||||
uart_data[priv->index].sw_rts.pin = NC;
|
||||
uart_data[priv->index].sw_cts.pin = NC;
|
||||
|
||||
/* Assign IRQ in advance and enable, all are masked anyways */
|
||||
NVIC_SetVector(irq_n, vector);
|
||||
#if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
|
||||
SCB_InvalidateICache();
|
||||
#endif
|
||||
NVIC_EnableIRQ(irq_n);
|
||||
|
||||
/* dissable IRQ by this if needed:
|
||||
NVIC_DisableIRQ(irq_n);
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // DEVICE_SERIAL
|
||||
Reference in New Issue
Block a user