uboot/drivers/serial/serial_stm32.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2015
   3 * Kamil Lulko, <kamil.lulko@gmail.com>
   4 *
   5 * SPDX-License-Identifier:     GPL-2.0+
   6 */
   7
   8#include <common.h>
   9#include <dm.h>
  10#include <asm/io.h>
  11#include <serial.h>
  12#include <asm/arch/stm32.h>
  13#include <dm/platform_data/serial_stm32.h>
  14
  15struct stm32_usart {
  16        u32 sr;
  17        u32 dr;
  18        u32 brr;
  19        u32 cr1;
  20        u32 cr2;
  21        u32 cr3;
  22        u32 gtpr;
  23};
  24
  25#define USART_CR1_RE                    (1 << 2)
  26#define USART_CR1_TE                    (1 << 3)
  27#define USART_CR1_UE                    (1 << 13)
  28
  29#define USART_SR_FLAG_RXNE      (1 << 5)
  30#define USART_SR_FLAG_TXE               (1 << 7)
  31
  32#define USART_BRR_F_MASK                0xF
  33#define USART_BRR_M_SHIFT       4
  34#define USART_BRR_M_MASK        0xFFF0
  35
  36DECLARE_GLOBAL_DATA_PTR;
  37
  38static int stm32_serial_setbrg(struct udevice *dev, int baudrate)
  39{
  40        struct stm32_serial_platdata *plat = dev->platdata;
  41        struct stm32_usart *const usart = plat->base;
  42        u32  clock, int_div, frac_div, tmp;
  43
  44        if (((u32)usart & STM32_BUS_MASK) == STM32_APB1PERIPH_BASE)
  45                clock = clock_get(CLOCK_APB1);
  46        else if (((u32)usart & STM32_BUS_MASK) == STM32_APB2PERIPH_BASE)
  47                clock = clock_get(CLOCK_APB2);
  48        else
  49                return -EINVAL;
  50
  51        int_div = (25 * clock) / (4 * baudrate);
  52        tmp = ((int_div / 100) << USART_BRR_M_SHIFT) & USART_BRR_M_MASK;
  53        frac_div = int_div - (100 * (tmp >> USART_BRR_M_SHIFT));
  54        tmp |= (((frac_div * 16) + 50) / 100) & USART_BRR_F_MASK;
  55        writel(tmp, &usart->brr);
  56
  57        return 0;
  58}
  59
  60static int stm32_serial_getc(struct udevice *dev)
  61{
  62        struct stm32_serial_platdata *plat = dev->platdata;
  63        struct stm32_usart *const usart = plat->base;
  64
  65        if ((readl(&usart->sr) & USART_SR_FLAG_RXNE) == 0)
  66                return -EAGAIN;
  67
  68        return readl(&usart->dr);
  69}
  70
  71static int stm32_serial_putc(struct udevice *dev, const char c)
  72{
  73        struct stm32_serial_platdata *plat = dev->platdata;
  74        struct stm32_usart *const usart = plat->base;
  75
  76        if ((readl(&usart->sr) & USART_SR_FLAG_TXE) == 0)
  77                return -EAGAIN;
  78
  79        writel(c, &usart->dr);
  80
  81        return 0;
  82}
  83
  84static int stm32_serial_pending(struct udevice *dev, bool input)
  85{
  86        struct stm32_serial_platdata *plat = dev->platdata;
  87        struct stm32_usart *const usart = plat->base;
  88
  89        if (input)
  90                return readl(&usart->sr) & USART_SR_FLAG_RXNE ? 1 : 0;
  91        else
  92                return readl(&usart->sr) & USART_SR_FLAG_TXE ? 0 : 1;
  93}
  94
  95static int stm32_serial_probe(struct udevice *dev)
  96{
  97        struct stm32_serial_platdata *plat = dev->platdata;
  98        struct stm32_usart *const usart = plat->base;
  99        setbits_le32(&usart->cr1, USART_CR1_RE | USART_CR1_TE | USART_CR1_UE);
 100
 101        return 0;
 102}
 103
 104static const struct dm_serial_ops stm32_serial_ops = {
 105        .putc = stm32_serial_putc,
 106        .pending = stm32_serial_pending,
 107        .getc = stm32_serial_getc,
 108        .setbrg = stm32_serial_setbrg,
 109};
 110
 111U_BOOT_DRIVER(serial_stm32) = {
 112        .name = "serial_stm32",
 113        .id = UCLASS_SERIAL,
 114        .ops = &stm32_serial_ops,
 115        .probe = stm32_serial_probe,
 116        .flags = DM_FLAG_PRE_RELOC,
 117};
 118