Prepare v2023.10
[platform/kernel/u-boot.git] / drivers / serial / serial_mpc8xx.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2000
4  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5  */
6
7 #include <common.h>
8 #include <command.h>
9 #include <dm.h>
10 #include <serial.h>
11 #include <watchdog.h>
12 #include <asm/cpm_8xx.h>
13 #include <asm/global_data.h>
14 #include <linux/compiler.h>
15
16 DECLARE_GLOBAL_DATA_PTR;
17
18 #if defined(CONFIG_8xx_CONS_SMC1)       /* Console on SMC1 */
19 #define SMC_INDEX       0
20 #define PROFF_SMC       PROFF_SMC1
21 #define CPM_CR_CH_SMC   CPM_CR_CH_SMC1
22 #define IOPINS          0xc0
23
24 #elif defined(CONFIG_8xx_CONS_SMC2)     /* Console on SMC2 */
25 #define SMC_INDEX       1
26 #define PROFF_SMC       PROFF_SMC2
27 #define CPM_CR_CH_SMC   CPM_CR_CH_SMC2
28 #define IOPINS          0xc00
29
30 #endif /* CONFIG_8xx_CONS_SMCx */
31
32 struct serialbuffer {
33         cbd_t   rxbd;           /* Rx BD */
34         cbd_t   txbd;           /* Tx BD */
35         uint    rxindex;        /* index for next character to read */
36         uchar   rxbuf[CONFIG_SYS_SMC_RXBUFLEN];/* rx buffers */
37         uchar   txbuf;  /* tx buffers */
38 };
39
40 static void serial_setdivisor(cpm8xx_t __iomem *cp, int baudrate)
41 {
42         int divisor = (gd->cpu_clk + 8 * baudrate) / 16 / baudrate;
43
44         if (divisor / 16 > 0x1000) {
45                 /* bad divisor, assume 50MHz clock and 9600 baud */
46                 divisor = (50 * 1000 * 1000 + 8 * 9600) / 16 / 9600;
47         }
48
49         divisor /= CONFIG_SYS_BRGCLK_PRESCALE;
50
51         if (divisor <= 0x1000)
52                 out_be32(&cp->cp_brgc1, ((divisor - 1) << 1) | CPM_BRG_EN);
53         else
54                 out_be32(&cp->cp_brgc1, ((divisor / 16 - 1) << 1) | CPM_BRG_EN |
55                          CPM_BRG_DIV16);
56 }
57
58 /*
59  * Minimal serial functions needed to use one of the SMC ports
60  * as serial console interface.
61  */
62
63 static int serial_mpc8xx_setbrg(struct udevice *dev, int baudrate)
64 {
65         immap_t __iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR;
66         cpm8xx_t __iomem *cp = &(im->im_cpm);
67
68         /* Set up the baud rate generator.
69          * See 8xx_io/commproc.c for details.
70          *
71          * Wire BRG1 to SMCx
72          */
73
74         out_be32(&cp->cp_simode, 0);
75
76         serial_setdivisor(cp, baudrate);
77
78         return 0;
79 }
80
81 static int serial_mpc8xx_probe(struct udevice *dev)
82 {
83         immap_t __iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR;
84         smc_t __iomem *sp;
85         smc_uart_t __iomem *up;
86         u16 smc_rpbase;
87         cpm8xx_t __iomem *cp = &(im->im_cpm);
88         struct serialbuffer __iomem *rtx;
89
90         /* initialize pointers to SMC */
91
92         sp = cp->cp_smc + SMC_INDEX;
93         up = (smc_uart_t __iomem *)&cp->cp_dpmem[PROFF_SMC];
94
95         smc_rpbase = in_be16(&up->smc_rpbase);
96         if (smc_rpbase)
97                 up = (smc_uart_t __iomem *)&cp->cp_dpmem[smc_rpbase];
98
99         /* Disable transmitter/receiver. */
100         clrbits_be16(&sp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
101
102         /* Enable SDMA. */
103         out_be32(&im->im_siu_conf.sc_sdcr, 1);
104
105         /* clear error conditions */
106         out_8(&im->im_sdma.sdma_sdsr, CONFIG_SYS_SDSR);
107
108         /* clear SDMA interrupt mask */
109         out_8(&im->im_sdma.sdma_sdmr, CONFIG_SYS_SDMR);
110
111         /* Use Port B for SMCx instead of other functions. */
112         setbits_be32(&cp->cp_pbpar, IOPINS);
113         clrbits_be32(&cp->cp_pbdir, IOPINS);
114         clrbits_be16(&cp->cp_pbodr, IOPINS);
115
116         /* Set the physical address of the host memory buffers in
117          * the buffer descriptors.
118          */
119         rtx = (struct serialbuffer __iomem *)&cp->cp_dpmem[CPM_SERIAL_BASE];
120         /* Allocate space for two buffer descriptors in the DP ram.
121          * For now, this address seems OK, but it may have to
122          * change with newer versions of the firmware.
123          * damm: allocating space after the two buffers for rx/tx data
124          */
125
126         out_be32(&rtx->rxbd.cbd_bufaddr, (__force uint)&rtx->rxbuf);
127         out_be16(&rtx->rxbd.cbd_sc, 0);
128
129         out_be32(&rtx->txbd.cbd_bufaddr, (__force uint)&rtx->txbuf);
130         out_be16(&rtx->txbd.cbd_sc, 0);
131
132         /* Set up the uart parameters in the parameter ram. */
133         out_be16(&up->smc_rbase, CPM_SERIAL_BASE);
134         out_be16(&up->smc_tbase, CPM_SERIAL_BASE + sizeof(cbd_t));
135         out_8(&up->smc_rfcr, SMC_EB);
136         out_8(&up->smc_tfcr, SMC_EB);
137
138         /* Set UART mode, 8 bit, no parity, one stop.
139          * Enable receive and transmit.
140          */
141         out_be16(&sp->smc_smcmr, smcr_mk_clen(9) | SMCMR_SM_UART);
142
143         /* Mask all interrupts and remove anything pending.
144         */
145         out_8(&sp->smc_smcm, 0);
146         out_8(&sp->smc_smce, 0xff);
147
148         /* Set up the baud rate generator */
149         serial_mpc8xx_setbrg(dev, gd->baudrate);
150
151         /* Make the first buffer the only buffer. */
152         setbits_be16(&rtx->txbd.cbd_sc, BD_SC_WRAP);
153         setbits_be16(&rtx->rxbd.cbd_sc, BD_SC_EMPTY | BD_SC_WRAP);
154
155         /* single/multi character receive. */
156         out_be16(&up->smc_mrblr, CONFIG_SYS_SMC_RXBUFLEN);
157         out_be16(&up->smc_maxidl, CONFIG_SYS_MAXIDLE);
158         out_be32(&rtx->rxindex, 0);
159
160         out_be32(&up->smc_rstate, 0);
161         out_be32(&up->smc_tstate, 0);
162         out_be16(&up->smc_rbptr, CPM_SERIAL_BASE);
163         out_be16(&up->smc_tbptr, CPM_SERIAL_BASE + sizeof(cbd_t));
164         out_be16(&up->smc_brkcr, 1);
165         out_be16(&up->smc_brkec, 0);
166
167         /* Enable transmitter/receiver. */
168         setbits_be16(&sp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
169
170         return 0;
171 }
172
173 static int serial_mpc8xx_putc(struct udevice *dev, const char c)
174 {
175         immap_t __iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR;
176         cpm8xx_t        __iomem *cpmp = &(im->im_cpm);
177         struct serialbuffer     __iomem *rtx;
178
179         rtx = (struct serialbuffer __iomem *)&cpmp->cp_dpmem[CPM_SERIAL_BASE];
180
181         if (in_be16(&rtx->txbd.cbd_sc) & BD_SC_READY)
182                 return -EAGAIN;
183
184         out_8(&rtx->txbuf, c);
185         out_be16(&rtx->txbd.cbd_datlen, 1);
186         setbits_be16(&rtx->txbd.cbd_sc, BD_SC_READY);
187
188         return 0;
189 }
190
191 static int serial_mpc8xx_getc(struct udevice *dev)
192 {
193         immap_t __iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR;
194         cpm8xx_t        __iomem *cpmp = &(im->im_cpm);
195         struct serialbuffer     __iomem *rtx;
196         unsigned char  c;
197         uint rxindex;
198
199         rtx = (struct serialbuffer __iomem *)&cpmp->cp_dpmem[CPM_SERIAL_BASE];
200
201         if (in_be16(&rtx->rxbd.cbd_sc) & BD_SC_EMPTY)
202                 return -EAGAIN;
203
204         /* the characters are read one by one,
205          * use the rxindex to know the next char to deliver
206          */
207         rxindex = in_be32(&rtx->rxindex);
208         c = in_8(rtx->rxbuf + rxindex);
209         rxindex++;
210
211         /* check if all char are readout, then make prepare for next receive */
212         if (rxindex >= in_be16(&rtx->rxbd.cbd_datlen)) {
213                 rxindex = 0;
214                 setbits_be16(&rtx->rxbd.cbd_sc, BD_SC_EMPTY);
215         }
216         out_be32(&rtx->rxindex, rxindex);
217         return c;
218 }
219
220 static int serial_mpc8xx_pending(struct udevice *dev, bool input)
221 {
222         immap_t __iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR;
223         cpm8xx_t        __iomem *cpmp = &(im->im_cpm);
224         struct serialbuffer     __iomem *rtx;
225
226         if (!input)
227                 return 0;
228
229         rtx = (struct serialbuffer __iomem *)&cpmp->cp_dpmem[CPM_SERIAL_BASE];
230
231         return !(in_be16(&rtx->rxbd.cbd_sc) & BD_SC_EMPTY);
232 }
233
234 static const struct dm_serial_ops serial_mpc8xx_ops = {
235         .putc = serial_mpc8xx_putc,
236         .pending = serial_mpc8xx_pending,
237         .getc = serial_mpc8xx_getc,
238         .setbrg = serial_mpc8xx_setbrg,
239 };
240
241 static const struct udevice_id serial_mpc8xx_ids[] = {
242         { .compatible = "fsl,pq1-smc" },
243         { }
244 };
245
246 U_BOOT_DRIVER(serial_mpc8xx) = {
247         .name   = "serial_mpc8xx",
248         .id     = UCLASS_SERIAL,
249         .of_match = serial_mpc8xx_ids,
250         .probe = serial_mpc8xx_probe,
251         .ops    = &serial_mpc8xx_ops,
252         .flags = DM_FLAG_PRE_RELOC,
253 };