Commit 72e57f02 authored by Yuri Tikhonov's avatar Yuri Tikhonov
Browse files

RT72064. stm32f2_usart: serial driver implementation


Signed-off-by: default avatarYuri Tikhonov <yur@emcraft.com>
parent e374df3e
......@@ -20,17 +20,110 @@
*/
#include <common.h>
#include <asm/arch/stm32f2.h>
#include "clock.h"
#if !defined(CONFIG_STM32F2_HSE_HZ)
# error "Value of the External oscillator, CONFIG_STM32F2_HSE_HZ, is not set."
#endif
/*
* Clock values
*/
static u32 clock_val[CLOCK_END];
/*
* Initialize the reference clocks.
*/
void clock_init(void)
{
static u32 apbahb_presc_tbl[] = {0, 0, 0, 0, 1, 2, 3, 4,
1, 2, 3, 4, 6, 7, 8, 9};
volatile struct stm32f2_rcc_regs *rcc_regs =
(struct stm32f2_rcc_regs *)STM32F2_RCC_BASE;
u32 tmp, presc, pllvco, pllp, pllm;
/*
* Get SYSCLK
*/
tmp = rcc_regs->cfgr >> STM32F2_RCC_CFGR_SWS_BIT;
tmp &= STM32F2_RCC_CFGR_SWS_MSK;
switch (tmp) {
case 0x00: /* HSI used as system clock source */
clock_val[CLOCK_SYSCLK] = STM32F2_HSI_HZ;
break;
case 0x04: /* HSE used as system clock source */
clock_val[CLOCK_SYSCLK] = CONFIG_STM32F2_HSE_HZ;
break;
case 0x08: /* PLL used as system clock source */
/*
* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLLM) * PLLN
* SYSCLK = PLL_VCO / PLLP
*/
pllm = rcc_regs->pllcfgr >> STM32F2_RCC_PLLCFGR_PLLM_BIT;
pllm &= STM32F2_RCC_PLLCFGR_PLLM_MSK;
if (rcc_regs->pllcfgr & (1 << STM32F2_RCC_PLLCFGR_PLLSRC_BIT)) {
/* HSE used as PLL clock source */
tmp = CONFIG_STM32F2_HSE_HZ;
} else {
/* HSI used as PLL clock source */
tmp = STM32F2_HSI_HZ;
}
pllvco = rcc_regs->pllcfgr >> STM32F2_RCC_PLLCFGR_PLLN_BIT;
pllvco &= STM32F2_RCC_PLLCFGR_PLLN_MSK;
pllvco *= tmp / pllm;
pllp = rcc_regs->pllcfgr >> STM32F2_RCC_PLLCFGR_PLLP_BIT;
pllp &= STM32F2_RCC_PLLCFGR_PLLP_MSK;
pllp = (pllp + 1) * 2;
clock_val[CLOCK_SYSCLK] = pllvco / pllp;
break;
default:
clock_val[CLOCK_SYSCLK] = STM32F2_HSI_HZ;
break;
}
/*
* TBD
* Get HCLK
*/
tmp = rcc_regs->cfgr >> STM32F2_RCC_CFGR_HPRE_BIT;
tmp &= STM32F2_RCC_CFGR_HPRE_MSK;
presc = apbahb_presc_tbl[tmp];
clock_val[CLOCK_HCLK] = clock_val[CLOCK_SYSCLK] >> presc;
/*
* Get PCLK1
*/
tmp = rcc_regs->cfgr >> STM32F2_RCC_CFGR_PPRE1_BIT;
tmp &= STM32F2_RCC_CFGR_PPRE1_MSK;
presc = apbahb_presc_tbl[tmp];
clock_val[CLOCK_PCLK1] = clock_val[CLOCK_HCLK] >> presc;
/*
* Get PCLK2
*/
tmp = rcc_regs->cfgr >> STM32F2_RCC_CFGR_PPRE2_BIT;
tmp &= STM32F2_RCC_CFGR_PPRE2_MSK;
presc = apbahb_presc_tbl[tmp];
clock_val[CLOCK_PCLK2] = clock_val[CLOCK_HCLK] >> presc;
return;
}
/*
* Return a clock value for the specified clock.
* Note that we need this function in RAM because it will be used
* during self-upgrade of U-boot into eNMV.
* @param clck id of the clock
* @returns frequency of the clock
*/
unsigned long __attribute__((section(".ramcode")))
__attribute__ ((long_call))
clock_get(enum clock clck)
{
return clock_val[clck];
}
......@@ -28,7 +28,6 @@ LIB := $(obj)libserial.a
COBJS-$(CONFIG_ARM_DCC) += arm_dcc.o
COBJS-$(CONFIG_AT91RM9200_USART) += at91rm9200_usart.o
COBJS-$(CONFIG_ATMEL_USART) += atmel_usart.o
COBJS-$(CONFIG_STM32F2_USART) += stm32f2_usart.o
COBJS-$(CONFIG_MCFUART) += mcfuart.o
COBJS-$(CONFIG_NS9750_UART) += ns9750_serial.o
COBJS-$(CONFIG_SYS_NS16550) += ns16550.o
......@@ -53,6 +52,7 @@ COBJS-$(CONFIG_S3C24X0_SERIAL) += serial_s3c24x0.o
COBJS-$(CONFIG_S3C44B0_SERIAL) += serial_s3c44b0.o
COBJS-$(CONFIG_XILINX_UARTLITE) += serial_xuartlite.o
COBJS-$(CONFIG_SCIF_CONSOLE) += serial_sh.o
COBJS-$(CONFIG_STM32F2_USART_CONSOLE) += stm32f2_usart.o
COBJS-$(CONFIG_USB_TTY) += usbtty.o
COBJS := $(sort $(COBJS-y))
......
......@@ -20,19 +20,203 @@
*/
/*
* STM32 F2 USART driver
* STM32 F2 USART driver; configured with the following options:
* - CONFIG_STM32F2_USART_CONSOLE
* - CONFIG_STM32F2_USART_PORT (1..6)
* - CONFIG_STM32F2_USART_TX_IO_PORT (1..9 <-> A..I)
* - CONFIG_STM32F2_USART_RX_IO_PORT (1..9 <-> A..I)
* - CONFIG_STM32F2_USART_TX_IO_PIN (1..16)
* - CONFIG_STM32F2_USART_RX_IO_PIN (1..16)
*/
#include <common.h>
#include <asm/arch/stm32f2.h>
/*
* Set up configuration
*/
#if (CONFIG_STM32F2_USART_PORT >= 1) && \
(CONFIG_STM32F2_USART_PORT <= 6)
# define USART_PORT (CONFIG_STM32F2_USART_PORT - 1)
#else
# error "Bad CONFIG_STM32F2_USART_PORT value."
#endif
#if (CONFIG_STM32F2_USART_TX_IO_PORT >= 1) && \
(CONFIG_STM32F2_USART_TX_IO_PORT <= 9)
# define USART_TX_IO_PORT (CONFIG_STM32F2_USART_TX_IO_PORT - 1)
#else
# error "Bad CONFIG_STM32F2_USART_TX_IO_PORT value."
#endif
#if (CONFIG_STM32F2_USART_RX_IO_PORT >= 1) && \
(CONFIG_STM32F2_USART_RX_IO_PORT <= 9)
# define USART_RX_IO_PORT (CONFIG_STM32F2_USART_RX_IO_PORT - 1)
#else
# error "Bad CONFIG_STM32F2_USART_RX_IO_PORT value."
#endif
#if (CONFIG_STM32F2_USART_TX_IO_PIN >= 0) && \
(CONFIG_STM32F2_USART_TX_IO_PIN <= 15)
# define USART_TX_IO_PIN (CONFIG_STM32F2_USART_TX_IO_PIN)
#else
# error "Bad CONFIG_STM32F2_USART_TX_IO_PIN value."
#endif
#if (CONFIG_STM32F2_USART_RX_IO_PIN >= 0) && \
(CONFIG_STM32F2_USART_RX_IO_PIN <= 15)
# define USART_RX_IO_PIN (CONFIG_STM32F2_USART_RX_IO_PIN)
#else
# error "Bad CONFIG_STM32F2_USART_RX_IO_PIN value."
#endif
DECLARE_GLOBAL_DATA_PTR;
/*
* Register map bases
*/
static const unsigned long usart_base[] = {
STM32F2_USART1_BASE, STM32F2_USART2_BASE, STM32F2_USART3_BASE,
STM32F2_USART4_BASE, STM32F2_USART5_BASE, STM32F2_USART6_BASE
};
static const unsigned long io_base[] = {
STM32F2_GPIOA_BASE, STM32F2_GPIOB_BASE, STM32F2_GPIOC_BASE,
STM32F2_GPIOD_BASE, STM32F2_GPIOE_BASE, STM32F2_GPIOF_BASE,
STM32F2_GPIOG_BASE, STM32F2_GPIOH_BASE, STM32F2_GPIOI_BASE
};
/*
* Regsiter offsets
*/
static const unsigned long rcc_enr_offset[] = {
STM32F2_RCC_ENR_USART1, STM32F2_RCC_ENR_USART2, STM32F2_RCC_ENR_USART3,
STM32F2_RCC_ENR_USART4, STM32F2_RCC_ENR_USART5, STM32F2_RCC_ENR_USART6
};
/*
* Different masks
*/
static const unsigned long rcc_msk[] = {
STM32F2_RCC_MSK_USART1, STM32F2_RCC_MSK_USART2, STM32F2_RCC_MSK_USART3,
STM32F2_RCC_MSK_USART4, STM32F2_RCC_MSK_USART5, STM32F2_RCC_MSK_USART6
};
static const unsigned long af_val[] = {
STM32F2_GPIO_AF_USART1, STM32F2_GPIO_AF_USART2, STM32F2_GPIO_AF_USART3,
STM32F2_GPIO_AF_USART4, STM32F2_GPIO_AF_USART5, STM32F2_GPIO_AF_USART6
};
/*
* Hardware resources
*/
static volatile struct stm32f2_usart_regs *usart_regs;
/*
* Initialize the serial port.
*/
int serial_init(void)
{
static volatile u32 *usart_enr;
static volatile struct stm32f2_rcc_regs *rcc_regs;
static volatile struct stm32f2_gpio_regs *io_regs[2];
static u32 io_ports[2];
static u32 io_pins[2];
u32 i, ofs;
/*
* GPIO params
*/
io_ports[0] = USART_TX_IO_PORT;
io_ports[1] = USART_RX_IO_PORT;
io_pins[0] = USART_TX_IO_PIN;
io_pins[1] = USART_RX_IO_PIN;
/*
* Setup registers
*/
usart_regs = (struct stm32f2_usart_regs *)usart_base[USART_PORT];
rcc_regs = (struct stm32f2_rcc_regs *)STM32F2_RCC_BASE;
for (i = 0; i < 2; i++)
io_regs[i] = (struct stm32f2_gpio_regs *)io_base[io_ports[i]];
usart_enr = (u32 *)(STM32F2_RCC_BASE + rcc_enr_offset[USART_PORT]);
/*
* Enable GPIO and USART clocks
*/
for (i = 0; i < 2; i++)
rcc_regs->ahb1enr |= 1 << io_ports[i];
*usart_enr |= rcc_msk[USART_PORT];
/*
* TBD
* Configure GPIOs
*/
for (i = 0; i < 2; i++) {
/*
* Connect PXy to USART Tx/Rx
*/
ofs = (io_pins[i] & 0x07) * 4;
io_regs[i]->afr[io_pins[i] >> 3] &= ~(0xF << ofs);
io_regs[i]->afr[io_pins[i] >> 3] |= af_val[USART_PORT] << ofs;
ofs = io_pins[i] * 2;
/*
* Set Alternative function mode
*/
io_regs[i]->moder &= ~(0x3 << ofs);
io_regs[i]->moder |= STM32F2_GPIO_MODE_AF << ofs;
/*
* Output mode configuration
*/
io_regs[i]->otyper &= ~(0x3 << ofs);
io_regs[i]->otyper |= STM32F2_GPIO_OTYPE_PP << ofs;
/*
* Speed mode configuration
*/
io_regs[i]->ospeedr &= ~(0x3 << ofs);
io_regs[i]->ospeedr |= STM32F2_GPIO_SPEED_50M << ofs;
/*
* Pull-up, pull down resistor configuration
*/
io_regs[i]->pupdr &= ~(0x3 << ofs);
io_regs[i]->pupdr |= STM32F2_GPIO_PUPD_UP;
}
/*
* CR1:
* - 1 Start bit, 8 Data bits, n Stop bit
* - parity control disabled
*/
usart_regs->cr1 = STM32F2_USART_CR1_TE | STM32F2_USART_CR1_RE;
/*
* CR2:
* - 1 Stop bit
*/
usart_regs->cr2 = 0;
/*
* CR3:
* - flow control disabled
* - full duplex
*/
usart_regs->cr3 = 0;
/*
* Set baudrate
*/
serial_setbrg();
/*
* Enable USART
*/
usart_regs->cr1 |= STM32F2_USART_CR1_UE;
return 0;
}
......@@ -42,9 +226,23 @@ int serial_init(void)
*/
void serial_setbrg(void)
{
u32 apb_clock, int_div, frac_div, tmp;
if (USART_PORT == 0 || USART_PORT == 5)
apb_clock = clock_get(CLOCK_PCLK2);
else
apb_clock = clock_get(CLOCK_PCLK1);
/*
* TBD
* Assume oversampling mode of 16 Samples
*/
int_div = (25 * apb_clock) / (4 * gd->baudrate);
tmp = (int_div / 100) << STM32F2_USART_BRR_MANT_BIT;
frac_div = int_div - (100 * (tmp >> 4));
tmp |= (((frac_div * 16) + 50) / 100) & STM32F2_USART_BRR_FRAC_MSK;
usart_regs->brr = tmp;
return;
}
......@@ -54,11 +252,9 @@ void serial_setbrg(void)
*/
int serial_getc(void)
{
/*
* TBD
*/
while (!(usart_regs->sr & STM32F2_USART_SR_RXNE));
return 0;
return usart_regs->dr & 0xFF;
}
/*
......@@ -66,11 +262,12 @@ int serial_getc(void)
*/
void serial_putc(const char c)
{
/*
* TBD
*/
if (c == '\n')
serial_putc('\r');
return;
while (!(usart_regs->sr & STM32F2_USART_SR_TXE));
usart_regs->dr = c;
}
/*
......@@ -87,11 +284,7 @@ void serial_puts(const char *s)
*/
int serial_tstc(void)
{
/*
* TBD
*/
return 0;
return (usart_regs->sr & STM32F2_USART_SR_RXNE) ? 1 : 0;
}
/*
* (C) Copyright 2011
*
* Yuri Tikhonov, Emcraft Systems, yur@emcraft.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 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
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
/*
* STM32F2 processor definitions
*/
#ifndef _MACH_STM32F2_H_
#define _MACH_STM32F2_H_
/******************************************************************************
* Peripheral memory map
******************************************************************************/
#define STM32F2_PERIPH_BASE 0x40000000
#define STM32F2_APB1PERITH_BASE (STM32F2_PERIPH_BASE + 0x00000000)
#define STM32F2_APB2PERITH_BASE (STM32F2_PERIPH_BASE + 0x00010000)
#define STM32F2_AHB1PERITH_BASE (STM32F2_PERIPH_BASE + 0x00020000)
#define STM32F2_AHB2PERITH_BASE (STM32F2_PERIPH_BASE + 0x10000000)
/******************************************************************************
* Universal Synchronous Asynchronous Receiver Transmitter
******************************************************************************/
/*
* USART register map
*/
struct stm32f2_usart_regs {
u16 sr; /* Status */
u16 rsv0;
u16 dr; /* Data */
u16 rsv1;
u16 brr; /* Baud rate */
u16 rsv2;
u16 cr1; /* Control 1 */
u16 rsv3;
u16 cr2; /* Control 2 */
u16 rsv4;
u16 cr3; /* Control 3 */
u16 rsv5;
u16 gtpr; /* Guard time and prescaler */
};
/*
* USART registers bases
*/
#define STM32F2_USART1_BASE (STM32F2_APB2PERITH_BASE + 0x1000)
#define STM32F2_USART2_BASE (STM32F2_APB1PERITH_BASE + 0x4400)
#define STM32F2_USART3_BASE (STM32F2_APB1PERITH_BASE + 0x4800)
#define STM32F2_USART4_BASE (STM32F2_APB1PERITH_BASE + 0x4C00)
#define STM32F2_USART5_BASE (STM32F2_APB1PERITH_BASE + 0x5000)
#define STM32F2_USART6_BASE (STM32F2_APB2PERITH_BASE + 0x1400)
/*
* SR bit masks
*/
#define STM32F2_USART_SR_TXE (1 << 7) /* Transmit data reg empty */
#define STM32F2_USART_SR_RXNE (1 << 5) /* Read data reg not empty */
/*
* BRR reg fields
*/
#define STM32F2_USART_BRR_FRAC_BIT 0 /* fraction of USARTDIV */
#define STM32F2_USART_BRR_FRAC_MSK 0x0F
#define STM32F2_USART_BRR_MANT_BIT 4 /* mantissa of USARTDIV */
#define STM32F2_USART_BRR_MANT_MSK 0xFFF
/*
* CR1 bit masks
*/
#define STM32F2_USART_CR1_UE (1 << 13) /* USART enable */
#define STM32F2_USART_CR1_TE (1 << 3) /* Transmitter enable */
#define STM32F2_USART_CR1_RE (1 << 2) /* Receiver enable */
/******************************************************************************
* Reset and Clock Control
******************************************************************************/
/*
* RCC register map
*/
struct stm32f2_rcc_regs {
u32 cr; /* RCC clock control */
u32 pllcfgr; /* RCC PLL configuration */
u32 cfgr; /* RCC clock configuration */
u32 cir; /* RCC clock interrupt */
u32 ahb1rstr; /* RCC AHB1 peripheral reset */
u32 ahb2rstr; /* RCC AHB2 peripheral reset */
u32 ahb3rstr; /* RCC AHB3 peripheral reset */
u32 rsv0;
u32 apb1rstr; /* RCC APB1 peripheral reset */
u32 apb2rstr; /* RCC APB2 peripheral reset */
u32 rsv1[2];
u32 ahb1enr; /* RCC AHB1 peripheral clock enable */
u32 ahb2enr; /* RCC AHB2 peripheral clock enable */
u32 ahb3enr; /* RCC AHB3 peripheral clock enable */
u32 rsv2;
u32 apb1enr; /* RCC APB1 peripheral clock enable */
u32 apb2enr; /* RCC APB2 peripheral clock enable */
u32 rsv3[2];
u32 ahb1lpenr; /* RCC AHB1 periph clk enable in low pwr mode */
u32 ahb2lpenr; /* RCC AHB2 periph clk enable in low pwr mode */
u32 ahb3lpenr; /* RCC AHB3 periph clk enable in low pwr mode */
u32 rsv4;
u32 apb1lpenr; /* RCC APB1 periph clk enable in low pwr mode */
u32 apb2lpenr; /* RCC APB2 periph clk enable in low pwr mode */
u32 rsv5[2];
u32 bdcr; /* RCC Backup domain control */
u32 csr; /* RCC clock control & status */
u32 rsv6[2];
u32 sscgr; /* RCC spread spectrum clock generation */
u32 plli2scfgr; /* RCC PLLI2S configuration */
};
/*
* Clocks enumeration
*/
enum clock {
CLOCK_SYSCLK, /* SYSCLK clock frequency expressed in Hz */
CLOCK_HCLK, /* HCLK clock frequency expressed in Hz */
CLOCK_PCLK1, /* PCLK1 clock frequency expressed in Hz */
CLOCK_PCLK2, /* PCLK2 clock frequency expressed in Hz */
CLOCK_END /* for internal usage */
};
/*
* RCC registers base
*/
#define STM32F2_RCC_BASE (STM32F2_AHB1PERITH_BASE + 0x3800)
/*
* Internal oscillator values
*/
#define STM32F2_HSI_HZ 16000000
/*
* Offsets and bitmasks of some RCC regs
*/
#define STM32F2_RCC_ENR_USART1 offsetof(struct stm32f2_rcc_regs, apb2enr)
#define STM32F2_RCC_MSK_USART1 (1 << 4)
#define STM32F2_RCC_ENR_USART2 offsetof(struct stm32f2_rcc_regs, apb1enr)
#define STM32F2_RCC_MSK_USART2 (1 << 17)
#define STM32F2_RCC_ENR_USART3 offsetof(struct stm32f2_rcc_regs, apb1enr)
#define STM32F2_RCC_MSK_USART3 (1 << 18)
#define STM32F2_RCC_ENR_USART4 offsetof(struct stm32f2_rcc_regs, apb1enr)
#define STM32F2_RCC_MSK_USART4 (1 << 19)
#define STM32F2_RCC_ENR_USART5 offsetof(struct stm32f2_rcc_regs, apb1enr)
#define STM32F2_RCC_MSK_USART5 (1 << 20)
#define STM32F2_RCC_ENR_USART6 offsetof(struct stm32f2_rcc_regs, apb2enr)
#define STM32F2_RCC_MSK_USART6 (1 << 5)
#define STM32F2_RCC_CFGR_SWS_BIT 0
#define STM32F2_RCC_CFGR_SWS_MSK 0x000F
#define STM32F2_RCC_CFGR_HPRE_BIT 4
#define STM32F2_RCC_CFGR_HPRE_MSK 0x000F
#define STM32F2_RCC_CFGR_PPRE1_BIT 10
#define STM32F2_RCC_CFGR_PPRE1_MSK 0x0007
#define STM32F2_RCC_CFGR_PPRE2_BIT 13
#define STM32F2_RCC_CFGR_PPRE2_MSK 0x0007
#define STM32F2_RCC_PLLCFGR_PLLSRC_BIT 22
#define STM32F2_RCC_PLLCFGR_PLLSRC_MSK 0x0001
#define STM32F2_RCC_PLLCFGR_PLLM_BIT 0
#define STM32F2_RCC_PLLCFGR_PLLM_MSK 0x003F
#define STM32F2_RCC_PLLCFGR_PLLN_BIT 6
#define STM32F2_RCC_PLLCFGR_PLLN_MSK 0x01FF
#define STM32F2_RCC_PLLCFGR_PLLP_BIT 16
#define STM32F2_RCC_PLLCFGR_PLLP_MSK 0x0003
/******************************************************************************
* General Purpose I/O
******************************************************************************/
/*
* GPIO register map
*/
struct stm32f2_gpio_regs {
u32 moder; /* GPIO port mode */
u32 otyper; /* GPIO port output type */
u32 ospeedr; /* GPIO port output speed */
u32 pupdr; /* GPIO port pull-up/pull-down */
u32 idr; /* GPIO port input data */
u32 odr; /* GPIO port output data */
u16 bsrrl; /* GPIO port bit set/reset low */
u16 bsrrh; /* GPIO port bit set/reset high */
u32 lckr; /* GPIO port configuration lock */
u32 afr[2]; /* GPIO alternate function */
};
/*
* GPIO registers bases
*/
#define STM32F2_GPIOA_BASE (STM32F2_AHB1PERITH_BASE + 0x0000)
#define STM32F2_GPIOB_BASE (STM32F2_AHB1PERITH_BASE + 0x0400)
#define STM32F2_GPIOC_BASE (STM32F2_AHB1PERITH_BASE + 0x0800)
#define STM32F2_GPIOD_BASE (STM32F2_AHB1PERITH_BASE + 0x0C00)
#define STM32F2_GPIOE_BASE (STM32F2_AHB1PERITH_BASE + 0x1000)
#define STM32F2_GPIOF_BASE (STM32F2_AHB1PERITH_BASE + 0x1400)