serial_mxc.c 10.7 KB
Newer Older
S
Sascha Hauer 已提交
1 2 3
/*
 * (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>
 *
4
 * SPDX-License-Identifier:	GPL-2.0+
S
Sascha Hauer 已提交
5 6 7
 */

#include <common.h>
8 9
#include <dm.h>
#include <errno.h>
10
#include <watchdog.h>
11 12
#include <asm/arch/imx-regs.h>
#include <asm/arch/clock.h>
13
#include <dm/platform_data/serial_mxc.h>
14 15
#include <serial.h>
#include <linux/compiler.h>
S
Sascha Hauer 已提交
16 17 18 19 20 21 22 23

/* UART Control Register Bit Fields.*/
#define  URXD_CHARRDY    (1<<15)
#define  URXD_ERR        (1<<14)
#define  URXD_OVRRUN     (1<<13)
#define  URXD_FRMERR     (1<<12)
#define  URXD_BRK        (1<<11)
#define  URXD_PRERR      (1<<10)
J
Juergen Kilb 已提交
24
#define  URXD_RX_DATA    (0xFF)
S
Sascha Hauer 已提交
25 26 27 28 29 30 31 32 33 34 35 36 37 38
#define  UCR1_ADEN       (1<<15) /* Auto dectect interrupt */
#define  UCR1_ADBR       (1<<14) /* Auto detect baud rate */
#define  UCR1_TRDYEN     (1<<13) /* Transmitter ready interrupt enable */
#define  UCR1_IDEN       (1<<12) /* Idle condition interrupt */
#define  UCR1_RRDYEN     (1<<9)	 /* Recv ready interrupt enable */
#define  UCR1_RDMAEN     (1<<8)	 /* Recv ready DMA enable */
#define  UCR1_IREN       (1<<7)	 /* Infrared interface enable */
#define  UCR1_TXMPTYEN   (1<<6)	 /* Transimitter empty interrupt enable */
#define  UCR1_RTSDEN     (1<<5)	 /* RTS delta interrupt enable */
#define  UCR1_SNDBRK     (1<<4)	 /* Send break */
#define  UCR1_TDMAEN     (1<<3)	 /* Transmitter ready DMA enable */
#define  UCR1_UARTCLKEN  (1<<2)	 /* UART clock enabled */
#define  UCR1_DOZE       (1<<1)	 /* Doze */
#define  UCR1_UARTEN     (1<<0)	 /* UART enabled */
W
Wolfgang Denk 已提交
39 40 41
#define  UCR2_ESCI	 (1<<15) /* Escape seq interrupt enable */
#define  UCR2_IRTS	 (1<<14) /* Ignore RTS pin */
#define  UCR2_CTSC	 (1<<13) /* CTS pin control */
S
Sascha Hauer 已提交
42 43 44 45 46 47 48 49 50
#define  UCR2_CTS        (1<<12) /* Clear to send */
#define  UCR2_ESCEN      (1<<11) /* Escape enable */
#define  UCR2_PREN       (1<<8)  /* Parity enable */
#define  UCR2_PROE       (1<<7)  /* Parity odd/even */
#define  UCR2_STPB       (1<<6)	 /* Stop */
#define  UCR2_WS         (1<<5)	 /* Word size */
#define  UCR2_RTSEN      (1<<4)	 /* Request to send interrupt enable */
#define  UCR2_TXEN       (1<<2)	 /* Transmitter enabled */
#define  UCR2_RXEN       (1<<1)	 /* Receiver enabled */
W
Wolfgang Denk 已提交
51 52
#define  UCR2_SRST	 (1<<0)	 /* SW reset */
#define  UCR3_DTREN	 (1<<13) /* DTR interrupt enable */
S
Sascha Hauer 已提交
53 54 55 56 57
#define  UCR3_PARERREN   (1<<12) /* Parity enable */
#define  UCR3_FRAERREN   (1<<11) /* Frame error interrupt enable */
#define  UCR3_DSR        (1<<10) /* Data set ready */
#define  UCR3_DCD        (1<<9)  /* Data carrier detect */
#define  UCR3_RI         (1<<8)  /* Ring indicator */
58
#define  UCR3_ADNIMP     (1<<7)  /* Autobaud Detection Not Improved */
S
Sascha Hauer 已提交
59 60 61
#define  UCR3_RXDSEN	 (1<<6)  /* Receive status interrupt enable */
#define  UCR3_AIRINTEN   (1<<5)  /* Async IR wake interrupt enable */
#define  UCR3_AWAKEN	 (1<<4)  /* Async wake interrupt enable */
W
Wolfgang Denk 已提交
62 63 64 65
#define  UCR3_REF25	 (1<<3)  /* Ref freq 25 MHz */
#define  UCR3_REF30	 (1<<2)  /* Ref Freq 30 MHz */
#define  UCR3_INVT	 (1<<1)  /* Inverted Infrared transmission */
#define  UCR3_BPEN	 (1<<0)  /* Preset registers enable */
S
Sascha Hauer 已提交
66
#define  UCR4_CTSTL_32   (32<<10) /* CTS trigger level (32 chars) */
W
Wolfgang Denk 已提交
67 68 69 70 71 72 73 74 75
#define  UCR4_INVR	 (1<<9)  /* Inverted infrared reception */
#define  UCR4_ENIRI	 (1<<8)  /* Serial infrared interrupt enable */
#define  UCR4_WKEN	 (1<<7)  /* Wake interrupt enable */
#define  UCR4_REF16	 (1<<6)  /* Ref freq 16 MHz */
#define  UCR4_IRSC	 (1<<5)  /* IR special case */
#define  UCR4_TCEN	 (1<<3)  /* Transmit complete interrupt enable */
#define  UCR4_BKEN	 (1<<2)  /* Break condition interrupt enable */
#define  UCR4_OREN	 (1<<1)  /* Receiver overrun interrupt enable */
#define  UCR4_DREN	 (1<<0)  /* Recv data ready interrupt enable */
S
Sascha Hauer 已提交
76 77
#define  UFCR_RXTL_SHF   0       /* Receiver trigger level shift */
#define  UFCR_RFDIV      (7<<7)  /* Reference freq divider mask */
78
#define  UFCR_RFDIV_SHF  7      /* Reference freq divider shift */
J
Jagan Teki 已提交
79
#define RFDIV		4 /* divide input clock by 2 */
80
#define  UFCR_DCEDTE	 (1<<6)  /* DTE mode select */
S
Sascha Hauer 已提交
81 82
#define  UFCR_TXTL_SHF   10      /* Transmitter trigger level shift */
#define  USR1_PARITYERR  (1<<15) /* Parity error interrupt flag */
W
Wolfgang Denk 已提交
83 84 85 86
#define  USR1_RTSS	 (1<<14) /* RTS pin status */
#define  USR1_TRDY	 (1<<13) /* Transmitter ready interrupt/dma flag */
#define  USR1_RTSD	 (1<<12) /* RTS delta */
#define  USR1_ESCF	 (1<<11) /* Escape seq interrupt flag */
S
Sascha Hauer 已提交
87 88 89
#define  USR1_FRAMERR    (1<<10) /* Frame error interrupt flag */
#define  USR1_RRDY       (1<<9)	 /* Receiver ready interrupt/dma flag */
#define  USR1_TIMEOUT    (1<<7)	 /* Receive timeout interrupt status */
W
Wolfgang Denk 已提交
90
#define  USR1_RXDS	 (1<<6)	 /* Receiver idle interrupt flag */
S
Sascha Hauer 已提交
91
#define  USR1_AIRINT	 (1<<5)	 /* Async IR wake interrupt flag */
W
Wolfgang Denk 已提交
92 93 94 95 96 97 98 99 100 101
#define  USR1_AWAKE	 (1<<4)	 /* Aysnc wake interrupt flag */
#define  USR2_ADET	 (1<<15) /* Auto baud rate detect complete */
#define  USR2_TXFE	 (1<<14) /* Transmit buffer FIFO empty */
#define  USR2_DTRF	 (1<<13) /* DTR edge interrupt flag */
#define  USR2_IDLE	 (1<<12) /* Idle condition */
#define  USR2_IRINT	 (1<<8)	 /* Serial infrared interrupt flag */
#define  USR2_WAKE	 (1<<7)	 /* Wake */
#define  USR2_RTSF	 (1<<4)	 /* RTS edge interrupt flag */
#define  USR2_TXDC	 (1<<3)	 /* Transmitter complete */
#define  USR2_BRCD	 (1<<2)	 /* Break condition */
S
Sascha Hauer 已提交
102 103 104 105 106 107
#define  USR2_ORE        (1<<1)	 /* Overrun error */
#define  USR2_RDR        (1<<0)	 /* Recv data ready */
#define  UTS_FRCPERR	 (1<<13) /* Force parity error */
#define  UTS_LOOP        (1<<12) /* Loop tx and rx */
#define  UTS_TXEMPTY	 (1<<6)	 /* TxFIFO empty */
#define  UTS_RXEMPTY	 (1<<5)	 /* RxFIFO empty */
W
Wolfgang Denk 已提交
108 109
#define  UTS_TXFULL	 (1<<4)	 /* TxFIFO full */
#define  UTS_RXFULL	 (1<<3)	 /* RxFIFO full */
J
Jagan Teki 已提交
110
#define  UTS_SOFTRS	(1<<0)	 /* Software reset */
S
Sascha Hauer 已提交
111

112 113
DECLARE_GLOBAL_DATA_PTR;

114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
struct mxc_uart {
	u32 rxd;
	u32 spare0[15];

	u32 txd;
	u32 spare1[15];

	u32 cr1;
	u32 cr2;
	u32 cr3;
	u32 cr4;

	u32 fcr;
	u32 sr1;
	u32 sr2;
	u32 esc;

	u32 tim;
	u32 bir;
	u32 bmr;
	u32 brc;

	u32 onems;
	u32 ts;
};

140 141 142 143 144 145
#ifndef CONFIG_DM_SERIAL

#ifndef CONFIG_MXC_UART_BASE
#error "define CONFIG_MXC_UART_BASE to use the MXC UART driver"
#endif

146
#define mxc_base	((struct mxc_uart *)CONFIG_MXC_UART_BASE)
147

148 149 150
#define TXTL  2 /* reset default */
#define RXTL  1 /* reset default */

151
static void mxc_serial_setbrg(void)
S
Sascha Hauer 已提交
152
{
153
	u32 clk = imx_get_uartclk();
S
Sascha Hauer 已提交
154 155 156 157

	if (!gd->baudrate)
		gd->baudrate = CONFIG_BAUDRATE;

158 159 160 161 162 163
	writel(((RFDIV << UFCR_RFDIV_SHF) |
		(TXTL << UFCR_TXTL_SHF) |
		(RXTL << UFCR_RXTL_SHF)),
		&mxc_base->fcr);
	writel(0xf, &mxc_base->bir);
	writel(clk / (2 * gd->baudrate), &mxc_base->bmr);
S
Sascha Hauer 已提交
164 165 166

}

167
static int mxc_serial_getc(void)
S
Sascha Hauer 已提交
168
{
169
	while (readl(&mxc_base->ts) & UTS_RXEMPTY)
170
		WATCHDOG_RESET();
171
	return (readl(&mxc_base->rxd) & URXD_RX_DATA); /* mask out status from upper word */
S
Sascha Hauer 已提交
172 173
}

174
static void mxc_serial_putc(const char c)
S
Sascha Hauer 已提交
175
{
176 177 178 179
	/* If \n, also do \r */
	if (c == '\n')
		serial_putc('\r');

180
	writel(c, &mxc_base->txd);
S
Sascha Hauer 已提交
181 182

	/* wait for transmitter to be ready */
183
	while (!(readl(&mxc_base->ts) & UTS_TXEMPTY))
184
		WATCHDOG_RESET();
S
Sascha Hauer 已提交
185 186 187 188 189
}

/*
 * Test whether a character is in the RX buffer
 */
190
static int mxc_serial_tstc(void)
S
Sascha Hauer 已提交
191 192
{
	/* If receive fifo is empty, return false */
193
	if (readl(&mxc_base->ts) & UTS_RXEMPTY)
S
Sascha Hauer 已提交
194 195 196 197 198 199 200 201 202
		return 0;
	return 1;
}

/*
 * Initialise the serial port with the given baudrate. The settings
 * are always 8 data bits, no parity, 1 stop bit, no start bits.
 *
 */
203
static int mxc_serial_init(void)
S
Sascha Hauer 已提交
204
{
205 206
	writel(0, &mxc_base->cr1);
	writel(0, &mxc_base->cr2);
S
Sascha Hauer 已提交
207

208
	while (!(readl(&mxc_base->cr2) & UCR2_SRST));
S
Sascha Hauer 已提交
209

210 211 212 213
	writel(0x704 | UCR3_ADNIMP, &mxc_base->cr3);
	writel(0x8000, &mxc_base->cr4);
	writel(0x2b, &mxc_base->esc);
	writel(0, &mxc_base->tim);
S
Sascha Hauer 已提交
214

215
	writel(0, &mxc_base->ts);
S
Sascha Hauer 已提交
216 217 218

	serial_setbrg();

219 220
	writel(UCR2_WS | UCR2_IRTS | UCR2_RXEN | UCR2_TXEN | UCR2_SRST,
	       &mxc_base->cr2);
S
Sascha Hauer 已提交
221

222
	writel(UCR1_UARTEN, &mxc_base->cr1);
S
Sascha Hauer 已提交
223 224 225

	return 0;
}
226 227 228 229 230 231 232

static struct serial_device mxc_serial_drv = {
	.name	= "mxc_serial",
	.start	= mxc_serial_init,
	.stop	= NULL,
	.setbrg	= mxc_serial_setbrg,
	.putc	= mxc_serial_putc,
233
	.puts	= default_serial_puts,
234 235 236 237 238 239 240 241 242 243 244 245 246
	.getc	= mxc_serial_getc,
	.tstc	= mxc_serial_tstc,
};

void mxc_serial_initialize(void)
{
	serial_register(&mxc_serial_drv);
}

__weak struct serial_device *default_serial_console(void)
{
	return &mxc_serial_drv;
}
247 248 249 250 251 252 253 254 255
#endif

#ifdef CONFIG_DM_SERIAL

int mxc_serial_setbrg(struct udevice *dev, int baudrate)
{
	struct mxc_serial_platdata *plat = dev->platdata;
	struct mxc_uart *const uart = plat->reg;
	u32 clk = imx_get_uartclk();
256 257
	u32 tmp;

J
Jagan Teki 已提交
258
	tmp = RFDIV << UFCR_RFDIV_SHF;
259 260 261
	if (plat->use_dte)
		tmp |= UFCR_DCEDTE;
	writel(tmp, &uart->fcr);
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332

	writel(0xf, &uart->bir);
	writel(clk / (2 * baudrate), &uart->bmr);

	writel(UCR2_WS | UCR2_IRTS | UCR2_RXEN | UCR2_TXEN | UCR2_SRST,
	       &uart->cr2);
	writel(UCR1_UARTEN, &uart->cr1);

	return 0;
}

static int mxc_serial_probe(struct udevice *dev)
{
	struct mxc_serial_platdata *plat = dev->platdata;
	struct mxc_uart *const uart = plat->reg;

	writel(0, &uart->cr1);
	writel(0, &uart->cr2);
	while (!(readl(&uart->cr2) & UCR2_SRST));
	writel(0x704 | UCR3_ADNIMP, &uart->cr3);
	writel(0x8000, &uart->cr4);
	writel(0x2b, &uart->esc);
	writel(0, &uart->tim);
	writel(0, &uart->ts);

	return 0;
}

static int mxc_serial_getc(struct udevice *dev)
{
	struct mxc_serial_platdata *plat = dev->platdata;
	struct mxc_uart *const uart = plat->reg;

	if (readl(&uart->ts) & UTS_RXEMPTY)
		return -EAGAIN;

	return readl(&uart->rxd) & URXD_RX_DATA;
}

static int mxc_serial_putc(struct udevice *dev, const char ch)
{
	struct mxc_serial_platdata *plat = dev->platdata;
	struct mxc_uart *const uart = plat->reg;

	if (!(readl(&uart->ts) & UTS_TXEMPTY))
		return -EAGAIN;

	writel(ch, &uart->txd);

	return 0;
}

static int mxc_serial_pending(struct udevice *dev, bool input)
{
	struct mxc_serial_platdata *plat = dev->platdata;
	struct mxc_uart *const uart = plat->reg;
	uint32_t sr2 = readl(&uart->sr2);

	if (input)
		return sr2 & USR2_RDR ? 1 : 0;
	else
		return sr2 & USR2_TXDC ? 0 : 1;
}

static const struct dm_serial_ops mxc_serial_ops = {
	.putc = mxc_serial_putc,
	.pending = mxc_serial_pending,
	.getc = mxc_serial_getc,
	.setbrg = mxc_serial_setbrg,
};

333 334 335 336 337 338
#if CONFIG_IS_ENABLED(OF_CONTROL)
static int mxc_serial_ofdata_to_platdata(struct udevice *dev)
{
	struct mxc_serial_platdata *plat = dev->platdata;
	fdt_addr_t addr;

S
Simon Glass 已提交
339
	addr = devfdt_get_addr(dev);
340 341 342 343 344
	if (addr == FDT_ADDR_T_NONE)
		return -EINVAL;

	plat->reg = (struct mxc_uart *)addr;

345
	plat->use_dte = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
346 347 348 349 350
					"fsl,dte-mode");
	return 0;
}

static const struct udevice_id mxc_serial_ids[] = {
351
	{ .compatible = "fsl,imx6ul-uart" },
352 353 354 355 356
	{ .compatible = "fsl,imx7d-uart" },
	{ }
};
#endif

357 358 359
U_BOOT_DRIVER(serial_mxc) = {
	.name	= "serial_mxc",
	.id	= UCLASS_SERIAL,
360 361 362 363 364
#if CONFIG_IS_ENABLED(OF_CONTROL)
	.of_match = mxc_serial_ids,
	.ofdata_to_platdata = mxc_serial_ofdata_to_platdata,
	.platdata_auto_alloc_size = sizeof(struct mxc_serial_platdata),
#endif
365 366 367 368 369
	.probe = mxc_serial_probe,
	.ops	= &mxc_serial_ops,
	.flags = DM_FLAG_PRE_RELOC,
};
#endif