]> Git Repo - J-u-boot.git/blob - drivers/serial/serial_npcm.c
Merge tag 'u-boot-imx-master-20250127' of https://gitlab.denx.de/u-boot/custodians...
[J-u-boot.git] / drivers / serial / serial_npcm.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2021 Nuvoton Technology Corp.
4  */
5
6 #include <clk.h>
7 #include <dm.h>
8 #include <serial.h>
9
10 struct npcm_uart {
11         union {
12                 u32     rbr;    /* Receive Buffer Register */
13                 u32     thr;    /* Transmit Holding Register */
14                 u32     dll;    /* Divisor Latch (Low Byte) Register */
15         };
16         union {
17                 u32     ier;    /* Interrupt Enable Register */
18                 u32     dlm;    /* Divisor Latch (Low Byte) Register */
19         };
20         union {
21                 u32     iir;    /* Interrupt Identification Register */
22                 u32     fcr;    /* FIFO Control Register */
23         };
24         u32     lcr;            /* Line Control Register */
25         u32     mcr;            /* Modem Control Register */
26         u32     lsr;            /* Line Status Control Register */
27         u32     msr;            /* Modem Status Register */
28         u32     tor;            /* Timeout Register */
29 };
30
31 #define LCR_WLS_8BITS   3       /* 8-bit word length select */
32 #define FCR_TFR         BIT(2)  /* TxFIFO reset */
33 #define FCR_RFR         BIT(1)  /* RxFIFO reset */
34 #define FCR_FME         BIT(0)  /* FIFO mode enable */
35 #define LSR_THRE        BIT(5)  /* Status of TxFIFO empty */
36 #define LSR_RFDR        BIT(0)  /* Status of RxFIFO data ready */
37 #define LCR_DLAB        BIT(7)  /* Divisor latch access bit */
38
39 struct npcm_serial_plat {
40         struct npcm_uart *reg;
41         u32 uart_clk;           /* frequency of uart clock source */
42 };
43
44 static int npcm_serial_pending(struct udevice *dev, bool input)
45 {
46         struct npcm_serial_plat *plat = dev_get_plat(dev);
47         struct npcm_uart *uart = plat->reg;
48
49         if (input)
50                 return readb(&uart->lsr) & LSR_RFDR ? 1 : 0;
51         else
52                 return readb(&uart->lsr) & LSR_THRE ? 0 : 1;
53 }
54
55 static int npcm_serial_putc(struct udevice *dev, const char ch)
56 {
57         struct npcm_serial_plat *plat = dev_get_plat(dev);
58         struct npcm_uart *uart = plat->reg;
59
60         if (!(readb(&uart->lsr) & LSR_THRE))
61                 return -EAGAIN;
62
63         writeb(ch, &uart->thr);
64
65         return 0;
66 }
67
68 static int npcm_serial_getc(struct udevice *dev)
69 {
70         struct npcm_serial_plat *plat = dev_get_plat(dev);
71         struct npcm_uart *uart = plat->reg;
72
73         if (!(readb(&uart->lsr) & LSR_RFDR))
74                 return -EAGAIN;
75
76         return readb(&uart->rbr);
77 }
78
79 static int npcm_serial_setbrg(struct udevice *dev, int baudrate)
80 {
81         struct npcm_serial_plat *plat = dev_get_plat(dev);
82         struct npcm_uart *uart = plat->reg;
83         u16 divisor;
84
85         if (IS_ENABLED(CONFIG_SYS_SKIP_UART_INIT))
86                 return 0;
87
88         /* BaudOut = UART Clock / (16 * [Divisor + 2]) */
89         divisor = DIV_ROUND_CLOSEST(plat->uart_clk, 16 * baudrate) - 2;
90
91         setbits_8(&uart->lcr, LCR_DLAB);
92         writeb(divisor & 0xff, &uart->dll);
93         writeb(divisor >> 8, &uart->dlm);
94         clrbits_8(&uart->lcr, LCR_DLAB);
95
96         return 0;
97 }
98
99 static int npcm_serial_probe(struct udevice *dev)
100 {
101         struct npcm_serial_plat *plat = dev_get_plat(dev);
102         struct npcm_uart *uart;
103         struct clk clk, parent;
104         u32 freq;
105         int ret;
106
107         plat->reg = dev_read_addr_ptr(dev);
108         uart = plat->reg;
109
110         if (!IS_ENABLED(CONFIG_SYS_SKIP_UART_INIT)) {
111                 freq = dev_read_u32_default(dev, "clock-frequency", 24000000);
112
113                 ret = clk_get_by_index(dev, 0, &clk);
114                 if (ret < 0)
115                         return ret;
116
117                 ret = clk_get_by_index(dev, 1, &parent);
118                 if (!ret) {
119                         ret = clk_set_parent(&clk, &parent);
120                         if (ret)
121                                 return ret;
122                 }
123
124                 if (freq) {
125                         ret = clk_set_rate(&clk, freq);
126                         if (ret < 0)
127                                 return ret;
128                 }
129                 plat->uart_clk = clk_get_rate(&clk);
130         }
131
132         /* Disable all interrupt */
133         writeb(0, &uart->ier);
134
135         /* Set 8 bit, 1 stop, no parity */
136         writeb(LCR_WLS_8BITS, &uart->lcr);
137
138         /* Reset RX/TX FIFO */
139         writeb(FCR_FME | FCR_RFR | FCR_TFR, &uart->fcr);
140
141         return 0;
142 }
143
144 static const struct dm_serial_ops npcm_serial_ops = {
145         .getc = npcm_serial_getc,
146         .setbrg = npcm_serial_setbrg,
147         .putc = npcm_serial_putc,
148         .pending = npcm_serial_pending,
149 };
150
151 static const struct udevice_id npcm_serial_ids[] = {
152         { .compatible = "nuvoton,npcm750-uart" },
153         { .compatible = "nuvoton,npcm845-uart" },
154         { }
155 };
156
157 U_BOOT_DRIVER(serial_npcm) = {
158         .name   = "serial_npcm",
159         .id     = UCLASS_SERIAL,
160         .of_match = npcm_serial_ids,
161         .plat_auto  = sizeof(struct npcm_serial_plat),
162         .probe = npcm_serial_probe,
163         .ops    = &npcm_serial_ops,
164         .flags = DM_FLAG_PRE_RELOC,
165 };
This page took 0.036322 seconds and 4 git commands to generate.