uboot/drivers/serial/serial_mvebu_a3700.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2016 Stefan Roese <sr@denx.de>
   3 *
   4 * SPDX-License-Identifier:     GPL-2.0+
   5 */
   6
   7#include <common.h>
   8#include <dm.h>
   9#include <serial.h>
  10#include <asm/io.h>
  11
  12struct mvebu_platdata {
  13        void __iomem *base;
  14};
  15
  16/*
  17 * Register offset
  18 */
  19#define UART_RX_REG             0x00
  20#define UART_TX_REG             0x04
  21#define UART_CTRL_REG           0x08
  22#define UART_STATUS_REG         0x0c
  23#define UART_BAUD_REG           0x10
  24#define UART_POSSR_REG          0x14
  25
  26#define UART_STATUS_RX_RDY      0x10
  27#define UART_STATUS_TXFIFO_FULL 0x800
  28
  29#define UART_CTRL_RXFIFO_RESET  0x4000
  30#define UART_CTRL_TXFIFO_RESET  0x8000
  31
  32#define CONFIG_UART_BASE_CLOCK  25804800
  33
  34static int mvebu_serial_putc(struct udevice *dev, const char ch)
  35{
  36        struct mvebu_platdata *plat = dev_get_platdata(dev);
  37        void __iomem *base = plat->base;
  38
  39        while (readl(base + UART_STATUS_REG) & UART_STATUS_TXFIFO_FULL)
  40                ;
  41
  42        writel(ch, base + UART_TX_REG);
  43
  44        return 0;
  45}
  46
  47static int mvebu_serial_getc(struct udevice *dev)
  48{
  49        struct mvebu_platdata *plat = dev_get_platdata(dev);
  50        void __iomem *base = plat->base;
  51
  52        while (!(readl(base + UART_STATUS_REG) & UART_STATUS_RX_RDY))
  53                ;
  54
  55        return readl(base + UART_RX_REG) & 0xff;
  56}
  57
  58static int mvebu_serial_pending(struct udevice *dev, bool input)
  59{
  60        struct mvebu_platdata *plat = dev_get_platdata(dev);
  61        void __iomem *base = plat->base;
  62
  63        if (readl(base + UART_STATUS_REG) & UART_STATUS_RX_RDY)
  64                return 1;
  65
  66        return 0;
  67}
  68
  69static int mvebu_serial_setbrg(struct udevice *dev, int baudrate)
  70{
  71        struct mvebu_platdata *plat = dev_get_platdata(dev);
  72        void __iomem *base = plat->base;
  73
  74        /*
  75         * Calculate divider
  76         * baudrate = clock / 16 / divider
  77         */
  78        writel(CONFIG_UART_BASE_CLOCK / baudrate / 16, base + UART_BAUD_REG);
  79
  80        /*
  81         * Set Programmable Oversampling Stack to 0,
  82         * UART defaults to 16x scheme
  83         */
  84        writel(0, base + UART_POSSR_REG);
  85
  86        return 0;
  87}
  88
  89static int mvebu_serial_probe(struct udevice *dev)
  90{
  91        struct mvebu_platdata *plat = dev_get_platdata(dev);
  92        void __iomem *base = plat->base;
  93
  94        /* reset FIFOs */
  95        writel(UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET,
  96               base + UART_CTRL_REG);
  97
  98        /* No Parity, 1 Stop */
  99        writel(0, base + UART_CTRL_REG);
 100
 101        return 0;
 102}
 103
 104static int mvebu_serial_ofdata_to_platdata(struct udevice *dev)
 105{
 106        struct mvebu_platdata *plat = dev_get_platdata(dev);
 107
 108        plat->base = devfdt_get_addr_ptr(dev);
 109
 110        return 0;
 111}
 112
 113static const struct dm_serial_ops mvebu_serial_ops = {
 114        .putc = mvebu_serial_putc,
 115        .pending = mvebu_serial_pending,
 116        .getc = mvebu_serial_getc,
 117        .setbrg = mvebu_serial_setbrg,
 118};
 119
 120static const struct udevice_id mvebu_serial_ids[] = {
 121        { .compatible = "marvell,armada-3700-uart" },
 122        { }
 123};
 124
 125U_BOOT_DRIVER(serial_mvebu) = {
 126        .name   = "serial_mvebu",
 127        .id     = UCLASS_SERIAL,
 128        .of_match = mvebu_serial_ids,
 129        .ofdata_to_platdata = mvebu_serial_ofdata_to_platdata,
 130        .platdata_auto_alloc_size = sizeof(struct mvebu_platdata),
 131        .probe  = mvebu_serial_probe,
 132        .ops    = &mvebu_serial_ops,
 133        .flags  = DM_FLAG_PRE_RELOC,
 134};
 135
 136#ifdef CONFIG_DEBUG_MVEBU_A3700_UART
 137
 138#include <debug_uart.h>
 139
 140static inline void _debug_uart_init(void)
 141{
 142        void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
 143
 144        /* reset FIFOs */
 145        writel(UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET,
 146               base + UART_CTRL_REG);
 147
 148        /* No Parity, 1 Stop */
 149        writel(0, base + UART_CTRL_REG);
 150
 151        /*
 152         * Calculate divider
 153         * baudrate = clock / 16 / divider
 154         */
 155        writel(CONFIG_UART_BASE_CLOCK / 115200 / 16, base + UART_BAUD_REG);
 156
 157        /*
 158         * Set Programmable Oversampling Stack to 0,
 159         * UART defaults to 16x scheme
 160         */
 161        writel(0, base + UART_POSSR_REG);
 162}
 163
 164static inline void _debug_uart_putc(int ch)
 165{
 166        void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
 167
 168        while (readl(base + UART_STATUS_REG) & UART_STATUS_TXFIFO_FULL)
 169                ;
 170
 171        writel(ch, base + UART_TX_REG);
 172}
 173
 174DEBUG_UART_FUNCS
 175#endif
 176