Commit 7e83dab7 authored by Alexander Potashev's avatar Alexander Potashev

RT74765. twr-k60n512: serial driver implementation

Also in this commit:
1. `kinetis_periph_enable()` for enabling clocks on various MCU modules.
2. Minimal GPIO driver with the `kinetis_gpio_config()` function.

FIFOs are not implemented in this driver (they can be enables via the
PFIFO, TXWATER and RXWATER registers), because on K60 only UART0
has a more than single-dataword FIFO, and UART0 is not used on the
TWR-K60N512 board.

We use the UART3 on the TWR-K60N512 board which is connected to the DB-9
port on the TWR-SER board in the TWR-K60N512-KIT board set.
parent 5c122449
......@@ -20,6 +20,7 @@
*/
#include <common.h>
#include <asm/errno.h>
#include "clock.h"
......@@ -249,6 +250,14 @@
/* Clock 4 output divider value (for the flash clock) */
#define KINETIS_SIM_CLKDIV1_OUTDIV4_BITS 16
/*
* Limits for the `kinetis_periph_enable()` function:
* 1. The number of SIM_SCGC[] registers
* 2. The number of bits in those registers
*/
#define KINETIS_SIM_CG_NUMREGS 7
#define KINETIS_SIM_CG_NUMBITS 32
/*
* System Integration Module (SIM) register map
*
......@@ -267,13 +276,7 @@ struct kinetis_sim_regs {
u32 sopt7; /* System Options Register 7 */
u32 rsv2[2];
u32 sdid; /* System Device Identification Register */
u32 scgc1; /* System Clock Gating Control Register 1 */
u32 scgc2; /* System Clock Gating Control Register 2 */
u32 scgc3; /* System Clock Gating Control Register 3 */
u32 scgc4; /* System Clock Gating Control Register 4 */
u32 scgc5; /* System Clock Gating Control Register 5 */
u32 scgc6; /* System Clock Gating Control Register 6 */
u32 scgc7; /* System Clock Gating Control Register 7 */
u32 scgc[7]; /* System Clock Gating Control Registers 1...7 */
u32 clkdiv1; /* System Clock Divider Register 1 */
u32 clkdiv2; /* System Clock Divider Register 2 */
u32 fcfg1; /* Flash Configuration Register 1 */
......@@ -497,6 +500,16 @@ void clock_init(void)
* On Kinetis, the SYSTICK rate is always equal to the CPU clock rate.
*/
clock_val[CLOCK_SYSTICK] = KINETIS_CPU_RATE;
/*
* Set the core/system clock rate
*/
clock_val[CLOCK_CCLK] = KINETIS_CPU_RATE;
/*
* Set the bus clock rate (used for many peripherals)
*/
clock_val[CLOCK_PCLK] = KINETIS_PCLK_RATE;
}
/*
......@@ -509,3 +522,34 @@ unsigned long clock_get(enum clock clck)
{
return clock_val[clck];
}
/*
* Enable or disable the clock on a peripheral device (timers, UARTs, USB, etc)
*/
int kinetis_periph_enable(kinetis_clock_gate_t gate, int enable)
{
volatile u32 *scgc;
u32 mask;
int rv;
/*
* Verify the function arguments
*/
if (KINETIS_CG_REG(gate) >= KINETIS_SIM_CG_NUMREGS ||
KINETIS_CG_IDX(gate) >= KINETIS_SIM_CG_NUMBITS) {
rv = -EINVAL;
goto out;
}
scgc = &KINETIS_SIM->scgc[KINETIS_CG_REG(gate)];
mask = 1 << KINETIS_CG_IDX(gate);
if (enable)
*scgc |= mask;
else
*scgc &= ~mask;
rv = 0;
out:
return rv;
}
......@@ -31,6 +31,7 @@ COBJS-$(CONFIG_MX31_GPIO) += mx31_gpio.o
COBJS-$(CONFIG_PCA953X) += pca953x.o
COBJS-$(CONFIG_STM32F2_GPIO) += stm32f2_gpio.o
COBJS-$(CONFIG_LPC178X_GPIO) += lpc178x_gpio.o
COBJS-$(CONFIG_KINETIS_GPIO) += kinetis_gpio.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
......
/*
* (C) Copyright 2011
*
* Alexander Potashev, Emcraft Systems, aspotashev@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
*/
#include <common.h>
#include <asm/errno.h>
#include <asm/arch/kinetis_gpio.h>
DECLARE_GLOBAL_DATA_PTR;
/*
* PORTx register map
*/
struct kinetis_port_regs {
u32 pcr[32]; /* Pin Control Registers */
u32 gpclr; /* Global Pin Control Low Register */
u32 gpchr; /* Global Pin Control High Register */
u32 rsv0[6];
u32 isfr; /* Interrupt Status Flag Register */
u32 rsv1[7];
u32 dfer; /* Digital Filter Enable Register */
u32 dfcr; /* Digital Filter Clock Register */
u32 dfwr; /* Digital Filter Width Register */
};
/*
* PORTx registers base
*/
#define KINETIS_PORT_BASE(port) (KINETIS_AIPS0PERIPH_BASE + \
0x00049000 + (port) * 0x1000)
#define KINETIS_PORT(port) ((volatile struct kinetis_port_regs *) \
KINETIS_PORT_BASE(port))
/*
* Clock gates for the I/O ports: 0..4 <-> A..E
*
* These values can be passed into the `kinetis_periph_enable()` function.
*/
static const kinetis_clock_gate_t port_clock_gate[] = {
KINETIS_CG_PORTA, KINETIS_CG_PORTB, KINETIS_CG_PORTC,
KINETIS_CG_PORTD, KINETIS_CG_PORTE
};
/*
* Check that the given (port, pin) pair is a valid Kinetis GPIO pin.
* Returns 0 on success, -EINVAL otherwise.
*/
static inline int kinetis_validate_gpio(const struct kinetis_gpio_dsc *dsc)
{
int rv;
rv = 0;
/*
* A[31:0]; B[31:0]; C[31:0]; D[31:0]; E[31:0]
*/
if (!dsc || dsc->port >= KINETIS_GPIO_PORTS ||
dsc->pin >= KINETIS_GPIO_PORT_PINS) {
if (gd->have_console) {
printf("GPIO: incorrect params %d.%d.\n",
dsc ? dsc->port : -1,
dsc ? dsc->pin : -1);
}
rv = -EINVAL;
}
return rv;
}
/*
* Configure the specified GPIO pin.
* The clocks on the necessary ports will be enabled automatically.
*
* Returns 0 on success, -EINVAL otherwise.
*/
int kinetis_gpio_config(const struct kinetis_gpio_dsc *dsc, u32 regval)
{
int rv;
/*
* Verify the function arguments
*/
rv = kinetis_validate_gpio(dsc);
if (rv != 0)
goto out;
/*
* Enable the clock on the port we are going to use
*/
rv = kinetis_periph_enable(port_clock_gate[dsc->port], 1);
if (rv != 0)
goto out;
/*
* Configure the pin
*/
KINETIS_PORT(dsc->port)->pcr[dsc->pin] = regval;
rv = 0;
out:
return rv;
}
......@@ -21,20 +21,261 @@
/*
* Freescale Kinetis UART driver
*
* Configured with the following options:
* CONFIG_KINETIS_UART_CONSOLE
* CONFIG_KINETIS_UART_PORT (0..5)
* CONFIG_KINETIS_UART_TX_IO_PORT (0..4 <-> A..E)
* CONFIG_KINETIS_UART_TX_IO_PIN (0..31)
* CONFIG_KINETIS_UART_TX_IO_FUNC (0..7, see the Pinout table)
* CONFIG_KINETIS_UART_RX_IO_PORT (0..4 <-> A..E)
* CONFIG_KINETIS_UART_RX_IO_PIN (0..31)
* CONFIG_KINETIS_UART_RX_IO_FUNC (0..7, see the Pinout table)
*/
#include <common.h>
#include <asm/arch/kinetis.h>
#include <asm/arch/kinetis_gpio.h>
/*
* Verify CONFIG_KINETIS_UART_PORT
*/
#if CONFIG_KINETIS_UART_PORT < 0 || CONFIG_KINETIS_UART_PORT > 5
#error CONFIG_KINETIS_UART_PORT should be between 0 and 5
#endif
/*
* Verify CONFIG_KINETIS_UART_TX_IO_PORT
*/
#if CONFIG_KINETIS_UART_TX_IO_PORT < 0 || CONFIG_KINETIS_UART_TX_IO_PORT > 4
#error CONFIG_KINETIS_UART_TX_IO_PORT should be between 0 and 4
#endif
/*
* Verify CONFIG_KINETIS_UART_TX_IO_PIN
*/
#if CONFIG_KINETIS_UART_TX_IO_PIN < 0 || CONFIG_KINETIS_UART_TX_IO_PIN > 31
#error CONFIG_KINETIS_UART_TX_IO_PIN should be between 0 and 31
#endif
/*
* Verify CONFIG_KINETIS_UART_TX_IO_FUNC
*/
#if CONFIG_KINETIS_UART_TX_IO_FUNC < 0 || CONFIG_KINETIS_UART_TX_IO_FUNC > 7
#error CONFIG_KINETIS_UART_TX_IO_FUNC should be between 0 and 7
#endif
/*
* Verify CONFIG_KINETIS_UART_RX_IO_PORT
*/
#if CONFIG_KINETIS_UART_RX_IO_PORT < 0 || CONFIG_KINETIS_UART_RX_IO_PORT > 4
#error CONFIG_KINETIS_UART_RX_IO_PORT should be between 0 and 4
#endif
/*
* Verify CONFIG_KINETIS_UART_RX_IO_PIN
*/
#if CONFIG_KINETIS_UART_RX_IO_PIN < 0 || CONFIG_KINETIS_UART_RX_IO_PIN > 31
#error CONFIG_KINETIS_UART_RX_IO_PIN should be between 0 and 31
#endif
/*
* Verify CONFIG_KINETIS_UART_RX_IO_FUNC
*/
#if CONFIG_KINETIS_UART_RX_IO_FUNC < 0 || CONFIG_KINETIS_UART_RX_IO_FUNC > 7
#error CONFIG_KINETIS_UART_RX_IO_FUNC should be between 0 and 7
#endif
/*
* Distrubution of the baudrate divisor value over the BDH/BDL registers and
* the C4[BRFA] bit field.
*/
/* C4[BRFA] (Baud Rate Fine Adjust) */
#define KINETIS_UART_BRFA_BITWIDTH 5
#define KINETIS_UART_BRFA_BITWIDTH_MSK ((1 << KINETIS_UART_BRFA_BITWIDTH) - 1)
/* BDL (Baud Rate Registers: Low) */
#define KINETIS_UART_BDL_BITWIDTH 8
#define KINETIS_UART_BDL_BITWIDTH_MSK ((1 << KINETIS_UART_BDL_BITWIDTH) - 1)
/* BDH (Baud Rate Registers: High) */
#define KINETIS_UART_BDH_BITWIDTH 5
#define KINETIS_UART_BDH_BITWIDTH_MSK ((1 << KINETIS_UART_BDH_BITWIDTH) - 1)
/*
* UART registers
*/
/*
* UART Baud Rate Registers: High
*/
#define KINETIS_UART_BDH_SBR_BITS 0
#define KINETIS_UART_BDH_SBR_MSK (KINETIS_UART_BDH_BITWIDTH_MSK << \
KINETIS_UART_BDH_SBR_BITS)
/*
* UART Baud Rate Registers: Low
*/
#define KINETIS_UART_BDL_SBR_BITS 0
/*
* UART Status Register 1
*/
/* Receive Data Register Full Flag */
#define KINETIS_UART_S1_RDRF_MSK (1 << 5)
/* Transmit Data Register Empty Flag */
#define KINETIS_UART_S1_TDRE_MSK (1 << 7)
/*
* UART Control Register 2
*/
/* Receiver Enable */
#define KINETIS_UART_C2_RE_MSK (1 << 2)
/* Transmitter Enable */
#define KINETIS_UART_C2_TE_MSK (1 << 3)
/*
* UART Control Register 4
*/
/* Baud Rate Fine Adjust */
#define KINETIS_UART_C4_BRFA_BITS 0
#define KINETIS_UART_C4_BRFA_MSK (KINETIS_UART_BRFA_BITWIDTH_MSK << \
KINETIS_UART_C4_BRFA_BITS)
/*
* UART registers bases
*/
#define KINETIS_UART0_BASE (KINETIS_AIPS0PERIPH_BASE + 0x0006A000)
#define KINETIS_UART1_BASE (KINETIS_AIPS0PERIPH_BASE + 0x0006B000)
#define KINETIS_UART2_BASE (KINETIS_AIPS0PERIPH_BASE + 0x0006C000)
#define KINETIS_UART3_BASE (KINETIS_AIPS0PERIPH_BASE + 0x0006D000)
#define KINETIS_UART4_BASE (KINETIS_AIPS1PERIPH_BASE + 0x0006A000)
#define KINETIS_UART5_BASE (KINETIS_AIPS1PERIPH_BASE + 0x0006B000)
/*
* UART register map
*/
struct kinetis_uart_regs {
u8 bdh; /* Baud Rate Registers: High */
u8 bdl; /* Baud Rate Registers: Low */
u8 c1; /* Control Register 1 */
u8 c2; /* Control Register 2 */
u8 s1; /* Status Register 1 */
u8 s2; /* Status Register 2 */
u8 c3; /* Control Register 3 */
u8 d; /* Data Register */
u8 m1; /* Match Address Registers 1 */
u8 m2; /* Match Address Registers 2 */
u8 c4; /* Control Register 4 */
u8 c5; /* Control Register 5 */
u8 ed; /* Extended Data Register */
u8 modem; /* Modem Register */
u8 ir; /* Infrared Register */
u8 rsv0;
u8 pfifo; /* FIFO Parameters */
u8 cfifo; /* FIFO Control Register */
u8 sfifo; /* FIFO Status Register */
u8 twfifo; /* FIFO Transmit Watermark */
u8 tcfifo; /* FIFO Transmit Count */
u8 rwfifo; /* FIFO Receive Watermark */
u8 rcfifo; /* FIFO Receive Count */
u8 rsv1;
u8 c7816; /* 7816 Control Register */
u8 ie7816; /* 7816 Interrupt Enable Register */
u8 is7816; /* 7816 Interrupt Status Register */
u8 wp7816t; /* 7816 Wait Parameter Register */
u8 wn7816; /* 7816 Wait N Register */
u8 wf7816; /* 7816 Wait FD Register */
u8 et7816; /* 7816 Error Threshold Register */
u8 tl7816; /* 7816 Transmit Length Register */
};
/*
* U-Boot global data to get the baudrate from
*/
DECLARE_GLOBAL_DATA_PTR;
/*
* UART registers bases
*/
static const u32 uart_base[] = {
KINETIS_UART0_BASE, KINETIS_UART1_BASE, KINETIS_UART2_BASE,
KINETIS_UART3_BASE, KINETIS_UART4_BASE, KINETIS_UART5_BASE
};
/*
* Clock gates for UARTs. These values can be passed
* into the `kinetis_periph_enable()` function.
*/
static const kinetis_clock_gate_t uart_clock_gate[] = {
KINETIS_CG_UART0, KINETIS_CG_UART1, KINETIS_CG_UART2,
KINETIS_CG_UART3, KINETIS_CG_UART4, KINETIS_CG_UART5
};
/*
* Hardware resources
*/
static volatile struct kinetis_uart_regs *uart_regs;
/*
* Initialize the serial port.
*/
int serial_init(void)
{
static struct kinetis_gpio_dsc tx_gpio = {
CONFIG_KINETIS_UART_TX_IO_PORT,
CONFIG_KINETIS_UART_TX_IO_PIN};
static struct kinetis_gpio_dsc rx_gpio = {
CONFIG_KINETIS_UART_RX_IO_PORT,
CONFIG_KINETIS_UART_RX_IO_PIN};
int rv;
/*
* Setup register map
*/
uart_regs = (volatile struct kinetis_uart_regs *)
uart_base[CONFIG_KINETIS_UART_PORT];
/*
* Enable clocks on the I/O ports and the UART used
*/
rv = kinetis_periph_enable(uart_clock_gate[CONFIG_KINETIS_UART_PORT], 1);
if (rv != 0)
goto out;
/*
* TBD
* Configure GPIO
*
* The clocks on the necessary ports will be enabled automatically.
*/
rv = kinetis_gpio_config(&tx_gpio,
KINETIS_GPIO_CONFIG_MUX(CONFIG_KINETIS_UART_TX_IO_FUNC));
if (rv != 0)
goto out;
rv = kinetis_gpio_config(&rx_gpio,
KINETIS_GPIO_CONFIG_MUX(CONFIG_KINETIS_UART_RX_IO_FUNC));
if (rv != 0)
goto out;
return 0;
/*
* CR1:
* - Start, 8 Data bits, Stop
* - parity control disabled
*/
uart_regs->c1 = 0;
/*
* Set baudrate
*/
serial_setbrg();
/*
* Enable receiver and transmitter
*/
uart_regs->c2 = KINETIS_UART_C2_RE_MSK | KINETIS_UART_C2_TE_MSK;
rv = 0;
out:
return rv;
}
/*
......@@ -42,11 +283,39 @@ int serial_init(void)
*/
void serial_setbrg(void)
{
u32 br_div;
/*
* TBD
* Configure baudrate
*
* UART0 and UART1 are clocked from the core clock, the remaining UARTs
* are clocked from the bus clock. The maximum baud rate is 1/16
* of the related source clock frequency.
*
* 32*SBR + BRFD = 2*clk / baudrate
*/
br_div = 2 * (CONFIG_KINETIS_UART_PORT <= 1 ?
clock_get(CLOCK_CCLK) : clock_get(CLOCK_PCLK)) / gd->baudrate;
return;
/*
* Baudrate fine adjust
*/
uart_regs->c4 =
(uart_regs->c4 & ~KINETIS_UART_C4_BRFA_MSK) |
((br_div & KINETIS_UART_BRFA_BITWIDTH_MSK) <<
KINETIS_UART_C4_BRFA_BITS);
/*
* Changes in BDH will not take effect until we write into BDL.
* Therefore we have to write into BDH first, and after that into BDL.
*/
uart_regs->bdh =
(uart_regs->bdh & ~KINETIS_UART_BDH_SBR_MSK) |
(((br_div >>
(KINETIS_UART_BRFA_BITWIDTH +
KINETIS_UART_BDL_BITWIDTH)) &
KINETIS_UART_BDH_BITWIDTH_MSK) << KINETIS_UART_BDH_SBR_BITS);
uart_regs->bdl =
((br_div >> KINETIS_UART_BRFA_BITWIDTH) & KINETIS_UART_BDL_BITWIDTH_MSK) << KINETIS_UART_BDL_SBR_BITS;
}
/*
......@@ -54,11 +323,9 @@ void serial_setbrg(void)
*/
int serial_getc(void)
{
/*
* TBD
*/
while (!(uart_regs->s1 & KINETIS_UART_S1_RDRF_MSK));
return 0;
return uart_regs->d;
}
/*
......@@ -66,11 +333,12 @@ int serial_getc(void)
*/
void serial_putc(const char c)
{
/*
* TBD
*/
if (c == '\n')
serial_putc('\r');
return;
while (!(uart_regs->s1 & KINETIS_UART_S1_TDRE_MSK));
uart_regs->d = c;
}
/*
......@@ -87,11 +355,6 @@ void serial_puts(const char *s)
*/
int serial_tstc(void)
{
/*
* TBD
*/
return 0;
return (uart_regs->s1 & KINETIS_UART_S1_RDRF_MSK) ? 1 : 0;
}
......@@ -42,12 +42,63 @@
* Peripheral memory map
*/
#define KINETIS_AIPS0PERIPH_BASE 0x40000000
#define KINETIS_AIPS1PERIPH_BASE 0x40080000
/*
* Pack the SIM_SCGC[] register index and the bit index in that register into
* a single word. This is similar to the implementation of `dev_t` in
* the Linux kernel with its `MAJOR(dev)`, `MINOR(dev)` and
* `MKDEV(major,minor)` macros.
*
* This is useful when you want to have an array of `kinetis_clock_gate_t`s:
* you do not have to use a 2-dimensional array or a real structure.
*/
typedef u32 kinetis_clock_gate_t;
#define KINETIS_CG_IDX_BITS 16
#define KINETIS_CG_IDX_MASK ((1U << KINETIS_CG_IDX_BITS) - 1)
/*
* Extract the register number and the bit index from a `kinetis_clock_gate_t`.
* The register number counts from 0,
* i.e. the register number for SIM_SCGC7 is 6.
*/
#define KINETIS_CG_REG(gate) ((unsigned int) ((gate) >> KINETIS_CG_IDX_BITS))
#define KINETIS_CG_IDX(gate) ((unsigned int) ((gate) & KINETIS_CG_IDX_MASK))
/*
* Build a `kinetis_clock_gate_t` from a register number and a bit index
*/
#define KINETIS_MKCG(reg,idx) \
(((kinetis_clock_gate_t)(reg) << KINETIS_CG_IDX_BITS) | \
(kinetis_clock_gate_t)(idx))
/*
* Clock gates for the modules inside the MCU
*/
/* UARTs */
#define KINETIS_CG_UART0 KINETIS_MKCG(3, 10) /* SIM_SCGC4[10] */
#define KINETIS_CG_UART1 KINETIS_MKCG(3, 11) /* SIM_SCGC4[11] */
#define KINETIS_CG_UART2 KINETIS_MKCG(3, 12) /* SIM_SCGC4[12] */
#define KINETIS_CG_UART3 KINETIS_MKCG(3, 13) /* SIM_SCGC4[13] */
#define KINETIS_CG_UART4 KINETIS_MKCG(0, 10) /* SIM_SCGC1[10] */
#define KINETIS_CG_UART5 KINETIS_MKCG(0, 11) /* SIM_SCGC1[11] */
/* Ports */
#define KINETIS_CG_PORTA KINETIS_MKCG(4, 9) /* SIM_SCGC5[9] */
#define KINETIS_CG_PORTB KINETIS_MKCG(4, 10) /* SIM_SCGC5[10] */
#define KINETIS_CG_PORTC KINETIS_MKCG(4, 11) /* SIM_SCGC5[11] */
#define KINETIS_CG_PORTD KINETIS_MKCG(4, 12) /* SIM_SCGC5[12] */
#define KINETIS_CG_PORTE KINETIS_MKCG(4, 13) /* SIM_SCGC5[13] */
/*
* Enable or disable the clock on a peripheral device (timers, UARTs, USB, etc)
*/
int kinetis_periph_enable(kinetis_clock_gate_t gate, int enable);
/*
* Clocks enumeration
*/
enum clock {
CLOCK_SYSTICK, /* Systimer clock frequency expressed in Hz */
CLOCK_CCLK, /* Core clock frequency expressed in Hz */
CLOCK_PCLK, /* Bus clock frequency expressed in Hz */
CLOCK_END /* for internal usage */
};
......
/*
* (C) Copyright 2011
*
* Alexander Potashev, Emcraft Systems, aspotashev@emcraft.com