uboot/drivers/serial/serial_lpuart.c
<<
>>
Prefs
   1/*
   2 * Copyright 2013 Freescale Semiconductor, Inc.
   3 *
   4 * SPDX-License-Identifier:     GPL-2.0+
   5 */
   6
   7#include <common.h>
   8#include <dm.h>
   9#include <fsl_lpuart.h>
  10#include <watchdog.h>
  11#include <asm/io.h>
  12#include <serial.h>
  13#include <linux/compiler.h>
  14#include <asm/arch/imx-regs.h>
  15#include <asm/arch/clock.h>
  16
  17#define US1_TDRE        (1 << 7)
  18#define US1_RDRF        (1 << 5)
  19#define US1_OR          (1 << 3)
  20#define UC2_TE          (1 << 3)
  21#define UC2_RE          (1 << 2)
  22#define CFIFO_TXFLUSH   (1 << 7)
  23#define CFIFO_RXFLUSH   (1 << 6)
  24#define SFIFO_RXOF      (1 << 2)
  25#define SFIFO_RXUF      (1 << 0)
  26
  27#define STAT_LBKDIF     (1 << 31)
  28#define STAT_RXEDGIF    (1 << 30)
  29#define STAT_TDRE       (1 << 23)
  30#define STAT_RDRF       (1 << 21)
  31#define STAT_IDLE       (1 << 20)
  32#define STAT_OR         (1 << 19)
  33#define STAT_NF         (1 << 18)
  34#define STAT_FE         (1 << 17)
  35#define STAT_PF         (1 << 16)
  36#define STAT_MA1F       (1 << 15)
  37#define STAT_MA2F       (1 << 14)
  38#define STAT_FLAGS      (STAT_LBKDIF | STAT_RXEDGIF | STAT_IDLE | STAT_OR | \
  39                         STAT_NF | STAT_FE | STAT_PF | STAT_MA1F | STAT_MA2F)
  40
  41#define CTRL_TE         (1 << 19)
  42#define CTRL_RE         (1 << 18)
  43
  44#define FIFO_TXFE               0x80
  45#define FIFO_RXFE               0x40
  46
  47#define WATER_TXWATER_OFF       1
  48#define WATER_RXWATER_OFF       16
  49
  50DECLARE_GLOBAL_DATA_PTR;
  51
  52#define LPUART_FLAG_REGMAP_32BIT_REG    BIT(0)
  53#define LPUART_FLAG_REGMAP_ENDIAN_BIG   BIT(1)
  54
  55enum lpuart_devtype {
  56        DEV_VF610 = 1,
  57        DEV_LS1021A,
  58        DEV_MX7ULP
  59};
  60
  61struct lpuart_serial_platdata {
  62        void *reg;
  63        enum lpuart_devtype devtype;
  64        ulong flags;
  65};
  66
  67static void lpuart_read32(u32 flags, u32 *addr, u32 *val)
  68{
  69        if (flags & LPUART_FLAG_REGMAP_32BIT_REG) {
  70                if (flags & LPUART_FLAG_REGMAP_ENDIAN_BIG)
  71                        *(u32 *)val = in_be32(addr);
  72                else
  73                        *(u32 *)val = in_le32(addr);
  74        }
  75}
  76
  77static void lpuart_write32(u32 flags, u32 *addr, u32 val)
  78{
  79        if (flags & LPUART_FLAG_REGMAP_32BIT_REG) {
  80                if (flags & LPUART_FLAG_REGMAP_ENDIAN_BIG)
  81                        out_be32(addr, val);
  82                else
  83                        out_le32(addr, val);
  84        }
  85}
  86
  87
  88#ifndef CONFIG_SYS_CLK_FREQ
  89#define CONFIG_SYS_CLK_FREQ     0
  90#endif
  91
  92u32 __weak get_lpuart_clk(void)
  93{
  94        return CONFIG_SYS_CLK_FREQ;
  95}
  96
  97static bool is_lpuart32(struct udevice *dev)
  98{
  99        struct lpuart_serial_platdata *plat = dev->platdata;
 100
 101        return plat->flags & LPUART_FLAG_REGMAP_32BIT_REG;
 102}
 103
 104static void _lpuart_serial_setbrg(struct lpuart_serial_platdata *plat,
 105                                  int baudrate)
 106{
 107        struct lpuart_fsl *base = plat->reg;
 108        u32 clk = get_lpuart_clk();
 109        u16 sbr;
 110
 111        sbr = (u16)(clk / (16 * baudrate));
 112
 113        /* place adjustment later - n/32 BRFA */
 114        __raw_writeb(sbr >> 8, &base->ubdh);
 115        __raw_writeb(sbr & 0xff, &base->ubdl);
 116}
 117
 118static int _lpuart_serial_getc(struct lpuart_serial_platdata *plat)
 119{
 120        struct lpuart_fsl *base = plat->reg;
 121        while (!(__raw_readb(&base->us1) & (US1_RDRF | US1_OR)))
 122                WATCHDOG_RESET();
 123
 124        barrier();
 125
 126        return __raw_readb(&base->ud);
 127}
 128
 129static void _lpuart_serial_putc(struct lpuart_serial_platdata *plat,
 130                                const char c)
 131{
 132        struct lpuart_fsl *base = plat->reg;
 133
 134        while (!(__raw_readb(&base->us1) & US1_TDRE))
 135                WATCHDOG_RESET();
 136
 137        __raw_writeb(c, &base->ud);
 138}
 139
 140/* Test whether a character is in the RX buffer */
 141static int _lpuart_serial_tstc(struct lpuart_serial_platdata *plat)
 142{
 143        struct lpuart_fsl *base = plat->reg;
 144
 145        if (__raw_readb(&base->urcfifo) == 0)
 146                return 0;
 147
 148        return 1;
 149}
 150
 151/*
 152 * Initialise the serial port with the given baudrate. The settings
 153 * are always 8 data bits, no parity, 1 stop bit, no start bits.
 154 */
 155static int _lpuart_serial_init(struct lpuart_serial_platdata *plat)
 156{
 157        struct lpuart_fsl *base = (struct lpuart_fsl *)plat->reg;
 158        u8 ctrl;
 159
 160        ctrl = __raw_readb(&base->uc2);
 161        ctrl &= ~UC2_RE;
 162        ctrl &= ~UC2_TE;
 163        __raw_writeb(ctrl, &base->uc2);
 164
 165        __raw_writeb(0, &base->umodem);
 166        __raw_writeb(0, &base->uc1);
 167
 168        /* Disable FIFO and flush buffer */
 169        __raw_writeb(0x0, &base->upfifo);
 170        __raw_writeb(0x0, &base->utwfifo);
 171        __raw_writeb(0x1, &base->urwfifo);
 172        __raw_writeb(CFIFO_TXFLUSH | CFIFO_RXFLUSH, &base->ucfifo);
 173
 174        /* provide data bits, parity, stop bit, etc */
 175        _lpuart_serial_setbrg(plat, gd->baudrate);
 176
 177        __raw_writeb(UC2_RE | UC2_TE, &base->uc2);
 178
 179        return 0;
 180}
 181
 182static void _lpuart32_serial_setbrg_7ulp(struct lpuart_serial_platdata *plat,
 183                                         int baudrate)
 184{
 185        struct lpuart_fsl_reg32 *base = plat->reg;
 186        u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, tmp;
 187        u32 clk = get_lpuart_clk();
 188
 189        baud_diff = baudrate;
 190        osr = 0;
 191        sbr = 0;
 192
 193        for (tmp_osr = 4; tmp_osr <= 32; tmp_osr++) {
 194                tmp_sbr = (clk / (baudrate * tmp_osr));
 195
 196                if (tmp_sbr == 0)
 197                        tmp_sbr = 1;
 198
 199                /*calculate difference in actual buad w/ current values */
 200                tmp_diff = (clk / (tmp_osr * tmp_sbr));
 201                tmp_diff = tmp_diff - baudrate;
 202
 203                /* select best values between sbr and sbr+1 */
 204                if (tmp_diff > (baudrate - (clk / (tmp_osr * (tmp_sbr + 1))))) {
 205                        tmp_diff = baudrate - (clk / (tmp_osr * (tmp_sbr + 1)));
 206                        tmp_sbr++;
 207                }
 208
 209                if (tmp_diff <= baud_diff) {
 210                        baud_diff = tmp_diff;
 211                        osr = tmp_osr;
 212                        sbr = tmp_sbr;
 213                }
 214        }
 215
 216        /*
 217         * TODO: handle buadrate outside acceptable rate
 218         * if (baudDiff > ((config->baudRate_Bps / 100) * 3))
 219         * {
 220         *   Unacceptable baud rate difference of more than 3%
 221         *   return kStatus_LPUART_BaudrateNotSupport;
 222         * }
 223         */
 224        tmp = in_le32(&base->baud);
 225
 226        if ((osr > 3) && (osr < 8))
 227                tmp |= LPUART_BAUD_BOTHEDGE_MASK;
 228
 229        tmp &= ~LPUART_BAUD_OSR_MASK;
 230        tmp |= LPUART_BAUD_OSR(osr-1);
 231
 232        tmp &= ~LPUART_BAUD_SBR_MASK;
 233        tmp |= LPUART_BAUD_SBR(sbr);
 234
 235        /* explicitly disable 10 bit mode & set 1 stop bit */
 236        tmp &= ~(LPUART_BAUD_M10_MASK | LPUART_BAUD_SBNS_MASK);
 237
 238        out_le32(&base->baud, tmp);
 239}
 240
 241static void _lpuart32_serial_setbrg(struct lpuart_serial_platdata *plat,
 242                                    int baudrate)
 243{
 244        struct lpuart_fsl_reg32 *base = plat->reg;
 245        u32 clk = get_lpuart_clk();
 246        u32 sbr;
 247
 248        sbr = (clk / (16 * baudrate));
 249
 250        /* place adjustment later - n/32 BRFA */
 251        lpuart_write32(plat->flags, &base->baud, sbr);
 252}
 253
 254static int _lpuart32_serial_getc(struct lpuart_serial_platdata *plat)
 255{
 256        struct lpuart_fsl_reg32 *base = plat->reg;
 257        u32 stat, val;
 258
 259        lpuart_read32(plat->flags, &base->stat, &stat);
 260        while ((stat & STAT_RDRF) == 0) {
 261                lpuart_write32(plat->flags, &base->stat, STAT_FLAGS);
 262                WATCHDOG_RESET();
 263                lpuart_read32(plat->flags, &base->stat, &stat);
 264        }
 265
 266        lpuart_read32(plat->flags, &base->data, &val);
 267
 268        if (plat->devtype & DEV_MX7ULP) {
 269                lpuart_read32(plat->flags, &base->stat, &stat);
 270                if (stat & STAT_OR)
 271                        lpuart_write32(plat->flags, &base->stat, STAT_OR);
 272        }
 273
 274        return val & 0x3ff;
 275}
 276
 277static void _lpuart32_serial_putc(struct lpuart_serial_platdata *plat,
 278                                  const char c)
 279{
 280        struct lpuart_fsl_reg32 *base = plat->reg;
 281        u32 stat;
 282
 283        if (plat->devtype & DEV_MX7ULP) {
 284                if (c == '\n')
 285                        serial_putc('\r');
 286        }
 287
 288        while (true) {
 289                lpuart_read32(plat->flags, &base->stat, &stat);
 290
 291                if ((stat & STAT_TDRE))
 292                        break;
 293
 294                WATCHDOG_RESET();
 295        }
 296
 297        lpuart_write32(plat->flags, &base->data, c);
 298}
 299
 300/* Test whether a character is in the RX buffer */
 301static int _lpuart32_serial_tstc(struct lpuart_serial_platdata *plat)
 302{
 303        struct lpuart_fsl_reg32 *base = plat->reg;
 304        u32 water;
 305
 306        lpuart_read32(plat->flags, &base->water, &water);
 307
 308        if ((water >> 24) == 0)
 309                return 0;
 310
 311        return 1;
 312}
 313
 314/*
 315 * Initialise the serial port with the given baudrate. The settings
 316 * are always 8 data bits, no parity, 1 stop bit, no start bits.
 317 */
 318static int _lpuart32_serial_init(struct lpuart_serial_platdata *plat)
 319{
 320        struct lpuart_fsl_reg32 *base = (struct lpuart_fsl_reg32 *)plat->reg;
 321        u32 ctrl;
 322
 323        lpuart_read32(plat->flags, &base->ctrl, &ctrl);
 324        ctrl &= ~CTRL_RE;
 325        ctrl &= ~CTRL_TE;
 326        lpuart_write32(plat->flags, &base->ctrl, ctrl);
 327
 328        lpuart_write32(plat->flags, &base->modir, 0);
 329        lpuart_write32(plat->flags, &base->fifo, ~(FIFO_TXFE | FIFO_RXFE));
 330
 331        lpuart_write32(plat->flags, &base->match, 0);
 332
 333        if (plat->devtype & DEV_MX7ULP) {
 334                _lpuart32_serial_setbrg_7ulp(plat, gd->baudrate);
 335        } else {
 336                /* provide data bits, parity, stop bit, etc */
 337                _lpuart32_serial_setbrg(plat, gd->baudrate);
 338        }
 339
 340        lpuart_write32(plat->flags, &base->ctrl, CTRL_RE | CTRL_TE);
 341
 342        return 0;
 343}
 344
 345static int lpuart_serial_setbrg(struct udevice *dev, int baudrate)
 346{
 347        struct lpuart_serial_platdata *plat = dev->platdata;
 348
 349        if (is_lpuart32(dev)) {
 350                if (plat->devtype & DEV_MX7ULP)
 351                        _lpuart32_serial_setbrg_7ulp(plat, baudrate);
 352                else
 353                        _lpuart32_serial_setbrg(plat, baudrate);
 354        } else {
 355                _lpuart_serial_setbrg(plat, baudrate);
 356        }
 357
 358        return 0;
 359}
 360
 361static int lpuart_serial_getc(struct udevice *dev)
 362{
 363        struct lpuart_serial_platdata *plat = dev->platdata;
 364
 365        if (is_lpuart32(dev))
 366                return _lpuart32_serial_getc(plat);
 367
 368        return _lpuart_serial_getc(plat);
 369}
 370
 371static int lpuart_serial_putc(struct udevice *dev, const char c)
 372{
 373        struct lpuart_serial_platdata *plat = dev->platdata;
 374
 375        if (is_lpuart32(dev))
 376                _lpuart32_serial_putc(plat, c);
 377        else
 378                _lpuart_serial_putc(plat, c);
 379
 380        return 0;
 381}
 382
 383static int lpuart_serial_pending(struct udevice *dev, bool input)
 384{
 385        struct lpuart_serial_platdata *plat = dev->platdata;
 386        struct lpuart_fsl *reg = plat->reg;
 387        struct lpuart_fsl_reg32 *reg32 = plat->reg;
 388        u32 stat;
 389
 390        if (is_lpuart32(dev)) {
 391                if (input) {
 392                        return _lpuart32_serial_tstc(plat);
 393                } else {
 394                        lpuart_read32(plat->flags, &reg32->stat, &stat);
 395                        return stat & STAT_TDRE ? 0 : 1;
 396                }
 397        }
 398
 399        if (input)
 400                return _lpuart_serial_tstc(plat);
 401        else
 402                return __raw_readb(&reg->us1) & US1_TDRE ? 0 : 1;
 403}
 404
 405static int lpuart_serial_probe(struct udevice *dev)
 406{
 407        struct lpuart_serial_platdata *plat = dev->platdata;
 408
 409        if (is_lpuart32(dev))
 410                return _lpuart32_serial_init(plat);
 411        else
 412                return _lpuart_serial_init(plat);
 413}
 414
 415static int lpuart_serial_ofdata_to_platdata(struct udevice *dev)
 416{
 417        struct lpuart_serial_platdata *plat = dev->platdata;
 418        const void *blob = gd->fdt_blob;
 419        int node = dev->of_offset;
 420        fdt_addr_t addr;
 421
 422        addr = dev_get_addr(dev);
 423        if (addr == FDT_ADDR_T_NONE)
 424                return -EINVAL;
 425
 426        plat->reg = (void *)addr;
 427        plat->flags = dev_get_driver_data(dev);
 428
 429        if (!fdt_node_check_compatible(blob, node, "fsl,ls1021a-lpuart"))
 430                plat->devtype = DEV_LS1021A;
 431        else if (!fdt_node_check_compatible(blob, node, "fsl,imx7ulp-lpuart"))
 432                plat->devtype = DEV_MX7ULP;
 433        else if (!fdt_node_check_compatible(blob, node, "fsl,vf610-lpuart"))
 434                plat->devtype = DEV_VF610;
 435
 436        return 0;
 437}
 438
 439static const struct dm_serial_ops lpuart_serial_ops = {
 440        .putc = lpuart_serial_putc,
 441        .pending = lpuart_serial_pending,
 442        .getc = lpuart_serial_getc,
 443        .setbrg = lpuart_serial_setbrg,
 444};
 445
 446static const struct udevice_id lpuart_serial_ids[] = {
 447        { .compatible = "fsl,ls1021a-lpuart", .data =
 448                LPUART_FLAG_REGMAP_32BIT_REG | LPUART_FLAG_REGMAP_ENDIAN_BIG },
 449        { .compatible = "fsl,imx7ulp-lpuart",
 450                .data = LPUART_FLAG_REGMAP_32BIT_REG },
 451        { .compatible = "fsl,vf610-lpuart"},
 452        { }
 453};
 454
 455U_BOOT_DRIVER(serial_lpuart) = {
 456        .name   = "serial_lpuart",
 457        .id     = UCLASS_SERIAL,
 458        .of_match = lpuart_serial_ids,
 459        .ofdata_to_platdata = lpuart_serial_ofdata_to_platdata,
 460        .platdata_auto_alloc_size = sizeof(struct lpuart_serial_platdata),
 461        .probe = lpuart_serial_probe,
 462        .ops    = &lpuart_serial_ops,
 463        .flags = DM_FLAG_PRE_RELOC,
 464};
 465