blob: c357e42187ad4f7d11a9b44a7c92f1136b94d52d [file] [log] [blame]
/****************************************************************************
* arch/arm/src/csk6/csk6_lowputc.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <arch/board/board.h>
#include "arm_internal.h"
#include "chip.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define CSK6_IOMUX_BASE 0x46200000 // size=1MB
#define CSK6_SYSCTRL_BASE 0x46000000 // size=64KB
#define CSK6_SYSPLL_CTRL_BASE 0x46020000 // size=64KB
#define CSK6_UART0_BASE 0x45000000 // size=1MB
#define CSK6011A_NANO_BOARD_H_XTAL_SRC_FREQ 24000000UL
#define CSK6011A_NANO_BOARD_L_XTAL_SRC_FREQ 32768UL
#define CSK6_IOMUX_PIN_OFFSET(pin) (pin << 2)
#define CSK6_IOMUX_FSEL_MASK (0X0f)
#define CSK6_IOMUX_FSEL_UART0 (0x2)
#define CSK6_UART0_TX_GPIO_PIN (2)
#define CSK6_UART0_RX_GPIO_PIN (3)
#define REG_FIELD_MASK(w, s) (((1U << (w)) - 1) << (s))
#define REG_FIELD_EXTRACT(v, w, s) ((v & REG_FIELD_MASK(w, s)) >> s)
#define REG_VALUE_SHIFT(v, s) (v << s)
/* Select USART parameters for the selected console */
#if defined(CONFIG_USART0_SERIAL_CONSOLE)
#define HAVE_CONSOLE
#define CSK6_CONSOLE_BASE() ((DW_UART_RegDef *)UART0_BASE)
#define CSK6_CONSOLE_BAUD CONFIG_USART0_BAUD
#define CSK6_CONSOLE_PARITY CONFIG_USART0_PARITY
#define CSK6_CONSOLE_NBITS CONFIG_USART0_BITS
#define CSK6_CONSOLE_2STOP CONFIG_USART0_2STOP
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
static inline float uart_compute_div(uint32_t baudrate, uint32_t clk)
{
uint32_t tmp = 16 * baudrate;
uint32_t div_i = clk / tmp;
float div_f = ((float)clk / (float)tmp) - div_i;
float div1 = div_i + (float)((uint32_t)(div_f * 16)) / 16.0;
float div2 = div_i + (float)((uint32_t)(div_f * 16) + 1) / 16.0;
int32_t err = clk - div1 * tmp;
int32_t err2 = div2 * tmp - clk;
if (err2 < 0)
{
err2 = err2 * (-1);
}
return err > err2 ? div2 : div1;
}
static inline void csk6_lowsetup_gpio_init(void)
{
modreg32(CSK6_IOMUX_FSEL_UART0,
CSK6_IOMUX_FSEL_MASK,
CSK6_IOMUX_BASE + CSK6_IOMUX_PIN_OFFSET(CSK6_UART0_TX_GPIO_PIN));
modreg32(CSK6_IOMUX_FSEL_UART0,
CSK6_IOMUX_FSEL_MASK,
CSK6_IOMUX_BASE + CSK6_IOMUX_PIN_OFFSET(CSK6_UART0_RX_GPIO_PIN));
}
static inline uint32_t get_uart0_clock(void)
{
uint32_t freq;
uint32_t pll_freq;
uint8_t div_n;
uint8_t div_m;
uint32_t reg_val;
reg_val = getreg32(CSK6_SYSCTRL_BASE + 0x3c);
div_n = REG_FIELD_EXTRACT(reg_val, 5, 25);
div_m = REG_FIELD_EXTRACT(reg_val, 5, 20) + 1;
if (!REG_FIELD_EXTRACT(reg_val, 1, 16)) /* CRM_IpSrcXtal */
{
freq = CSK6011A_NANO_BOARD_H_XTAL_SRC_FREQ;
}
else /* CRM_IpSrcSysPllPeri */
{
uint32_t div;
reg_val = getreg32(CSK6_SYSCTRL_BASE + 0x30);
div = REG_FIELD_EXTRACT(reg_val, 2, 29) + 10;
pll_freq = CSK6011A_NANO_BOARD_H_XTAL_SRC_FREQ *
REG_FIELD_EXTRACT(getreg32(CSK6_SYSPLL_CTRL_BASE + 0x14), 7, 1) /
(REG_FIELD_EXTRACT(
getreg32(CSK6_SYSPLL_CTRL_BASE + 0x14), 4, 8)
+ 1);
freq = pll_freq / div;
}
return freq * div_n / div_m;
}
static inline void csk6_uart_clock_enable(void)
{
modreg32(REG_VALUE_SHIFT(0x01, 19),
REG_FIELD_MASK(1, 19),
CSK6_SYSCTRL_BASE + 0x3c);
}
/****************************************************************************
* Public Functions
****************************************************************************/
#if defined(HAVE_CONSOLE)
/****************************************************************************
* Name: arm_lowputc
*
* Description:
* Output one byte on the serial console
*
****************************************************************************/
void arm_lowputc(char ch)
{
while (!REG_FIELD_EXTRACT(getreg32(CSK6_UART0_BASE + 0x14), 1, 6))
{
}
putreg32(ch, CSK6_UART0_BASE + 0x00);
}
/****************************************************************************
* Name: csk6_lowsetup
*
* Description:
* This performs basic initialization of the USART used for the serial
* console. Its purpose is to get the console output available as soon
* as possible.
*
****************************************************************************/
void csk6_lowsetup(void)
{
uint32_t uart_clock = 0;
float div;
uint32_t div_i;
uint32_t div_f;
csk6_lowsetup_gpio_init();
csk6_uart_clock_enable();
uart_clock = get_uart0_clock();
/* disable all */
putreg32(0, CSK6_UART0_BASE + 0x04);
div = uart_compute_div(CSK6_CONSOLE_BAUD, uart_clock);
div_i = (uint32_t)div;
div_f = (div - div_i) * 16;
modreg32(REG_VALUE_SHIFT(0x01, 7),
REG_FIELD_MASK(1, 7),
CSK6_UART0_BASE + 0x0c);
modreg32(REG_VALUE_SHIFT(div_i, 0),
REG_FIELD_MASK(8, 0),
CSK6_UART0_BASE + 0x00);
modreg32(REG_VALUE_SHIFT(div_i >> 8, 0),
REG_FIELD_MASK(8, 0),
CSK6_UART0_BASE + 0x04);
modreg32(REG_VALUE_SHIFT(div_f, 0),
REG_FIELD_MASK(4, 0),
CSK6_UART0_BASE + 0xc0);
modreg32(REG_VALUE_SHIFT(0x00, 0),
REG_FIELD_MASK(1, 7),
CSK6_UART0_BASE + 0x0c);
#if (CSK6_CONSOLE_PARITY == 1)
modreg32(REG_VALUE_SHIFT(0x01, 3),
REG_FIELD_MASK(1, 3),
CSK6_UART0_BASE + 0x0c);
modreg32(REG_VALUE_SHIFT(0x01, 3),
REG_FIELD_MASK(1, 4),
CSK6_UART0_BASE + 0x0c);
#elif (CSK6_CONSOLE_PARITY == 2)
modreg32(REG_VALUE_SHIFT(0x01, 3),
REG_FIELD_MASK(1, 3),
CSK6_UART0_BASE + 0x0c);
modreg32(REG_VALUE_SHIFT(0x00, 3),
REG_FIELD_MASK(1, 4),
CSK6_UART0_BASE + 0x0c);
#else
modreg32(REG_VALUE_SHIFT(0x00, 3),
REG_FIELD_MASK(1, 3),
CSK6_UART0_BASE + 0x0c);
#endif
#if (CSK6_CONSOLE_NBITS == 5)
modreg32(REG_VALUE_SHIFT(0x00, 0),
REG_FIELD_MASK(2, 0),
CSK6_UART0_BASE + 0x0c);
#elif (CSK6_CONSOLE_NBITS == 6)
modreg32(REG_VALUE_SHIFT(0x00, 0),
REG_FIELD_MASK(2, 0),
CSK6_UART0_BASE + 0x0c);
#elif (CSK6_CONSOLE_NBITS == 7)
modreg32(REG_VALUE_SHIFT(0x00, 0),
REG_FIELD_MASK(2, 0),
CSK6_UART0_BASE + 0x0c);
#else
modreg32(REG_VALUE_SHIFT(0x03, 0),
REG_FIELD_MASK(2, 0),
CSK6_UART0_BASE + 0x0c);
#endif
#if (CSK6_CONSOLE_2STOP)
modreg32(REG_VALUE_SHIFT(0x01, 2),
REG_FIELD_MASK(1, 2),
CSK6_UART0_BASE + 0x0c);
#else
modreg32(REG_VALUE_SHIFT(0x00, 2),
REG_FIELD_MASK(1, 2),
CSK6_UART0_BASE + 0x0c);
#endif
putreg32(REG_VALUE_SHIFT(0x02, 4) | REG_VALUE_SHIFT(0x01, 0),
CSK6_UART0_BASE + 0x08); /* set fifo */
}
#else
void arm_lowputc(char ch)
{
}
void csk6_lowsetup(void)
{
}
#endif