uboot/drivers/serial/atmel_usart.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2004-2006 Atmel Corporation
   4 *
   5 * Modified to support C structur SoC access by
   6 * Andreas Bießmann <biessmann@corscience.de>
   7 */
   8#include <common.h>
   9#include <clk.h>
  10#include <dm.h>
  11#include <errno.h>
  12#include <malloc.h>
  13#include <watchdog.h>
  14#include <serial.h>
  15#include <debug_uart.h>
  16#include <linux/compiler.h>
  17#include <linux/delay.h>
  18
  19#include <asm/io.h>
  20#ifdef CONFIG_DM_SERIAL
  21#include <asm/arch/atmel_serial.h>
  22#endif
  23#include <asm/arch/clk.h>
  24#include <asm/arch/hardware.h>
  25
  26#include "atmel_usart.h"
  27
  28DECLARE_GLOBAL_DATA_PTR;
  29
  30#ifndef CONFIG_DM_SERIAL
  31static void atmel_serial_setbrg_internal(atmel_usart3_t *usart, int id,
  32                                         int baudrate)
  33{
  34        unsigned long divisor;
  35        unsigned long usart_hz;
  36
  37        /*
  38         *              Master Clock
  39         * Baud Rate = --------------
  40         *                16 * CD
  41         */
  42        usart_hz = get_usart_clk_rate(id);
  43        divisor = (usart_hz / 16 + baudrate / 2) / baudrate;
  44        writel(USART3_BF(CD, divisor), &usart->brgr);
  45}
  46
  47static void atmel_serial_init_internal(atmel_usart3_t *usart)
  48{
  49        /*
  50         * Just in case: drain transmitter register
  51         * 1000us is enough for baudrate >= 9600
  52         */
  53        if (!(readl(&usart->csr) & USART3_BIT(TXEMPTY)))
  54                __udelay(1000);
  55
  56        writel(USART3_BIT(RSTRX) | USART3_BIT(RSTTX), &usart->cr);
  57}
  58
  59static void atmel_serial_activate(atmel_usart3_t *usart)
  60{
  61        writel((USART3_BF(USART_MODE, USART3_USART_MODE_NORMAL)
  62                           | USART3_BF(USCLKS, USART3_USCLKS_MCK)
  63                           | USART3_BF(CHRL, USART3_CHRL_8)
  64                           | USART3_BF(PAR, USART3_PAR_NONE)
  65                           | USART3_BF(NBSTOP, USART3_NBSTOP_1)),
  66                           &usart->mr);
  67        writel(USART3_BIT(RXEN) | USART3_BIT(TXEN), &usart->cr);
  68        /* 100us is enough for the new settings to be settled */
  69        __udelay(100);
  70}
  71
  72static void atmel_serial_setbrg(void)
  73{
  74        atmel_serial_setbrg_internal((atmel_usart3_t *)CONFIG_USART_BASE,
  75                                     CONFIG_USART_ID, gd->baudrate);
  76}
  77
  78static int atmel_serial_init(void)
  79{
  80        atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE;
  81
  82        atmel_serial_init_internal(usart);
  83        serial_setbrg();
  84        atmel_serial_activate(usart);
  85
  86        return 0;
  87}
  88
  89static void atmel_serial_putc(char c)
  90{
  91        atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE;
  92
  93        if (c == '\n')
  94                serial_putc('\r');
  95
  96        while (!(readl(&usart->csr) & USART3_BIT(TXRDY)));
  97        writel(c, &usart->thr);
  98}
  99
 100static int atmel_serial_getc(void)
 101{
 102        atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE;
 103
 104        while (!(readl(&usart->csr) & USART3_BIT(RXRDY)))
 105                 WATCHDOG_RESET();
 106        return readl(&usart->rhr);
 107}
 108
 109static int atmel_serial_tstc(void)
 110{
 111        atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE;
 112        return (readl(&usart->csr) & USART3_BIT(RXRDY)) != 0;
 113}
 114
 115static struct serial_device atmel_serial_drv = {
 116        .name   = "atmel_serial",
 117        .start  = atmel_serial_init,
 118        .stop   = NULL,
 119        .setbrg = atmel_serial_setbrg,
 120        .putc   = atmel_serial_putc,
 121        .puts   = default_serial_puts,
 122        .getc   = atmel_serial_getc,
 123        .tstc   = atmel_serial_tstc,
 124};
 125
 126void atmel_serial_initialize(void)
 127{
 128        serial_register(&atmel_serial_drv);
 129}
 130
 131__weak struct serial_device *default_serial_console(void)
 132{
 133        return &atmel_serial_drv;
 134}
 135#endif
 136
 137#ifdef CONFIG_DM_SERIAL
 138enum serial_clk_type {
 139        CLK_TYPE_NORMAL = 0,
 140        CLK_TYPE_DBGU,
 141};
 142
 143struct atmel_serial_priv {
 144        atmel_usart3_t *usart;
 145        ulong usart_clk_rate;
 146};
 147
 148static void _atmel_serial_set_brg(atmel_usart3_t *usart,
 149                                  ulong usart_clk_rate, int baudrate)
 150{
 151        unsigned long divisor;
 152
 153        divisor = (usart_clk_rate / 16 + baudrate / 2) / baudrate;
 154        writel(USART3_BF(CD, divisor), &usart->brgr);
 155}
 156
 157void _atmel_serial_init(atmel_usart3_t *usart,
 158                        ulong usart_clk_rate, int baudrate)
 159{
 160        writel(USART3_BIT(RXDIS) | USART3_BIT(TXDIS), &usart->cr);
 161
 162        writel((USART3_BF(USART_MODE, USART3_USART_MODE_NORMAL) |
 163                USART3_BF(USCLKS, USART3_USCLKS_MCK) |
 164                USART3_BF(CHRL, USART3_CHRL_8) |
 165                USART3_BF(PAR, USART3_PAR_NONE) |
 166                USART3_BF(NBSTOP, USART3_NBSTOP_1)), &usart->mr);
 167
 168        _atmel_serial_set_brg(usart, usart_clk_rate, baudrate);
 169
 170        writel(USART3_BIT(RSTRX) | USART3_BIT(RSTTX), &usart->cr);
 171        writel(USART3_BIT(RXEN) | USART3_BIT(TXEN), &usart->cr);
 172}
 173
 174int atmel_serial_setbrg(struct udevice *dev, int baudrate)
 175{
 176        struct atmel_serial_priv *priv = dev_get_priv(dev);
 177
 178        _atmel_serial_set_brg(priv->usart, priv->usart_clk_rate, baudrate);
 179
 180        return 0;
 181}
 182
 183static int atmel_serial_getc(struct udevice *dev)
 184{
 185        struct atmel_serial_priv *priv = dev_get_priv(dev);
 186
 187        if (!(readl(&priv->usart->csr) & USART3_BIT(RXRDY)))
 188                return -EAGAIN;
 189
 190        return readl(&priv->usart->rhr);
 191}
 192
 193static int atmel_serial_putc(struct udevice *dev, const char ch)
 194{
 195        struct atmel_serial_priv *priv = dev_get_priv(dev);
 196
 197        if (!(readl(&priv->usart->csr) & USART3_BIT(TXRDY)))
 198                return -EAGAIN;
 199
 200        writel(ch, &priv->usart->thr);
 201
 202        return 0;
 203}
 204
 205static int atmel_serial_pending(struct udevice *dev, bool input)
 206{
 207        struct atmel_serial_priv *priv = dev_get_priv(dev);
 208        uint32_t csr = readl(&priv->usart->csr);
 209
 210        if (input)
 211                return csr & USART3_BIT(RXRDY) ? 1 : 0;
 212        else
 213                return csr & USART3_BIT(TXEMPTY) ? 0 : 1;
 214}
 215
 216static const struct dm_serial_ops atmel_serial_ops = {
 217        .putc = atmel_serial_putc,
 218        .pending = atmel_serial_pending,
 219        .getc = atmel_serial_getc,
 220        .setbrg = atmel_serial_setbrg,
 221};
 222
 223#if defined(CONFIG_SPL_BUILD) && !defined(CONFIG_SPL_CLK)
 224static int atmel_serial_enable_clk(struct udevice *dev)
 225{
 226        struct atmel_serial_priv *priv = dev_get_priv(dev);
 227
 228        /* Use fixed clock value in SPL */
 229        priv->usart_clk_rate = CONFIG_SPL_UART_CLOCK;
 230
 231        return 0;
 232}
 233#else
 234static int atmel_serial_enable_clk(struct udevice *dev)
 235{
 236        struct atmel_serial_priv *priv = dev_get_priv(dev);
 237        struct clk clk;
 238        ulong clk_rate;
 239        int ret;
 240
 241        ret = clk_get_by_index(dev, 0, &clk);
 242        if (ret)
 243                return -EINVAL;
 244
 245        if (dev_get_driver_data(dev) == CLK_TYPE_NORMAL) {
 246                ret = clk_enable(&clk);
 247                if (ret)
 248                        return ret;
 249        }
 250
 251        clk_rate = clk_get_rate(&clk);
 252        if (!clk_rate)
 253                return -EINVAL;
 254
 255        priv->usart_clk_rate = clk_rate;
 256
 257        clk_free(&clk);
 258
 259        return 0;
 260}
 261#endif
 262
 263static int atmel_serial_probe(struct udevice *dev)
 264{
 265        struct atmel_serial_platdata *plat = dev->platdata;
 266        struct atmel_serial_priv *priv = dev_get_priv(dev);
 267        int ret;
 268#if CONFIG_IS_ENABLED(OF_CONTROL)
 269        fdt_addr_t addr_base;
 270
 271        addr_base = dev_read_addr(dev);
 272        if (addr_base == FDT_ADDR_T_NONE)
 273                return -ENODEV;
 274
 275        plat->base_addr = (uint32_t)addr_base;
 276#endif
 277        priv->usart = (atmel_usart3_t *)plat->base_addr;
 278
 279        ret = atmel_serial_enable_clk(dev);
 280        if (ret)
 281                return ret;
 282
 283        _atmel_serial_init(priv->usart, priv->usart_clk_rate, gd->baudrate);
 284
 285        return 0;
 286}
 287
 288#if CONFIG_IS_ENABLED(OF_CONTROL)
 289static const struct udevice_id atmel_serial_ids[] = {
 290        {
 291                .compatible = "atmel,at91sam9260-dbgu",
 292                .data = CLK_TYPE_DBGU,
 293        },
 294        {
 295                .compatible = "atmel,at91sam9260-usart",
 296                .data = CLK_TYPE_NORMAL,
 297        },
 298        { }
 299};
 300#endif
 301
 302U_BOOT_DRIVER(serial_atmel) = {
 303        .name   = "serial_atmel",
 304        .id     = UCLASS_SERIAL,
 305#if CONFIG_IS_ENABLED(OF_CONTROL)
 306        .of_match = atmel_serial_ids,
 307        .platdata_auto_alloc_size = sizeof(struct atmel_serial_platdata),
 308#endif
 309        .probe = atmel_serial_probe,
 310        .ops    = &atmel_serial_ops,
 311#if !CONFIG_IS_ENABLED(OF_CONTROL)
 312        .flags = DM_FLAG_PRE_RELOC,
 313#endif
 314        .priv_auto_alloc_size   = sizeof(struct atmel_serial_priv),
 315};
 316#endif
 317
 318#ifdef CONFIG_DEBUG_UART_ATMEL
 319static inline void _debug_uart_init(void)
 320{
 321        atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_DEBUG_UART_BASE;
 322
 323        _atmel_serial_init(usart, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
 324}
 325
 326static inline void _debug_uart_putc(int ch)
 327{
 328        atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_DEBUG_UART_BASE;
 329
 330        while (!(readl(&usart->csr) & USART3_BIT(TXRDY)))
 331                ;
 332
 333        writel(ch, &usart->thr);
 334}
 335
 336DEBUG_UART_FUNCS
 337#endif
 338