mirror of
				https://source.denx.de/u-boot/u-boot.git
				synced 2025-10-31 16:31:25 +01:00 
			
		
		
		
	Uniformize all STMicroelectronics copyrights headers for STi related code. Signed-off-by: Patrice Chotard <patrice.chotard@st.com>
		
			
				
	
	
		
			212 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			212 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Support for Serial I/O using STMicroelectronics' on-chip ASC.
 | |
|  *
 | |
|  * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
 | |
|  * Author(s): Patrice Chotard, <patrice.chotard@st.com> for STMicroelectronics.
 | |
|  *
 | |
|  * SPDX-License-Identifier:	GPL-2.0+
 | |
|  */
 | |
| 
 | |
| #include <common.h>
 | |
| #include <dm.h>
 | |
| #include <serial.h>
 | |
| #include <asm/io.h>
 | |
| 
 | |
| DECLARE_GLOBAL_DATA_PTR;
 | |
| 
 | |
| #define BAUDMODE	0x00001000
 | |
| #define RXENABLE	0x00000100
 | |
| #define RUN		0x00000080
 | |
| #define MODE		0x00000001
 | |
| #define MODE_8BIT	0x0001
 | |
| #define STOP_1BIT	0x0008
 | |
| #define PARITYODD	0x0020
 | |
| 
 | |
| #define STA_TF		BIT(9)
 | |
| #define STA_RBF		BIT(0)
 | |
| 
 | |
| struct sti_asc_uart {
 | |
| 	u32 baudrate;
 | |
| 	u32 txbuf;
 | |
| 	u32 rxbuf;
 | |
| 	u32 control;
 | |
| 	u32 inten;
 | |
| 	u32 status;
 | |
| 	u32 guardtime;
 | |
| 	u32 timeout;
 | |
| 	u32 txreset;
 | |
| 	u32 rxreset;
 | |
| };
 | |
| 
 | |
| struct sti_asc_serial {
 | |
| 	/* address of registers in physical memory */
 | |
| 	struct sti_asc_uart *regs;
 | |
| };
 | |
| 
 | |
| /* Values for the BAUDRATE Register */
 | |
| #define PCLK			(200ul * 1000000ul)
 | |
| #define BAUDRATE_VAL_M0(bps)	(PCLK / (16 * (bps)))
 | |
| #define BAUDRATE_VAL_M1(bps)	((bps * (1 << 14)) + (1<<13)) / (PCLK/(1 << 6))
 | |
| 
 | |
| /*
 | |
|  * MODE 0
 | |
|  *                       ICCLK
 | |
|  * ASCBaudRate =   ----------------
 | |
|  *                   baudrate * 16
 | |
|  *
 | |
|  * MODE 1
 | |
|  *                   baudrate * 16 * 2^16
 | |
|  * ASCBaudRate =   ------------------------
 | |
|  *                          ICCLK
 | |
|  *
 | |
|  * NOTE:
 | |
|  * Mode 1 should be used for baudrates of 19200, and above, as it
 | |
|  * has a lower deviation error than Mode 0 for higher frequencies.
 | |
|  * Mode 0 should be used for all baudrates below 19200.
 | |
|  */
 | |
| 
 | |
| static int sti_asc_pending(struct udevice *dev, bool input)
 | |
| {
 | |
| 	struct sti_asc_serial *priv = dev_get_priv(dev);
 | |
| 	struct sti_asc_uart *const uart = priv->regs;
 | |
| 	unsigned long status;
 | |
| 
 | |
| 	status = readl(&uart->status);
 | |
| 	if (input)
 | |
| 		return status & STA_RBF;
 | |
| 	else
 | |
| 		return status & STA_TF;
 | |
| }
 | |
| 
 | |
| static int _sti_asc_serial_setbrg(struct sti_asc_uart *uart, int baudrate)
 | |
| {
 | |
| 	unsigned long val;
 | |
| 	int t, mode = 1;
 | |
| 
 | |
| 	switch (baudrate) {
 | |
| 	case 9600:
 | |
| 		t = BAUDRATE_VAL_M0(9600);
 | |
| 		mode = 0;
 | |
| 		break;
 | |
| 	case 19200:
 | |
| 		t = BAUDRATE_VAL_M1(19200);
 | |
| 		break;
 | |
| 	case 38400:
 | |
| 		t = BAUDRATE_VAL_M1(38400);
 | |
| 		break;
 | |
| 	case 57600:
 | |
| 		t = BAUDRATE_VAL_M1(57600);
 | |
| 		break;
 | |
| 	default:
 | |
| 		debug("ASC: unsupported baud rate: %d, using 115200 instead.\n",
 | |
| 		      baudrate);
 | |
| 	case 115200:
 | |
| 		t = BAUDRATE_VAL_M1(115200);
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	/* disable the baudrate generator */
 | |
| 	val = readl(&uart->control);
 | |
| 	writel(val & ~RUN, &uart->control);
 | |
| 
 | |
| 	/* set baud generator reload value */
 | |
| 	writel(t, &uart->baudrate);
 | |
| 	/* reset the RX & TX buffers */
 | |
| 	writel(1, &uart->txreset);
 | |
| 	writel(1, &uart->rxreset);
 | |
| 
 | |
| 	/* set baud generator mode */
 | |
| 	if (mode)
 | |
| 		val |= BAUDMODE;
 | |
| 
 | |
| 	/* finally, write value and enable ASC */
 | |
| 	writel(val, &uart->control);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /* called to adjust baud-rate */
 | |
| static int sti_asc_serial_setbrg(struct udevice *dev, int baudrate)
 | |
| {
 | |
| 	struct sti_asc_serial *priv = dev_get_priv(dev);
 | |
| 	struct sti_asc_uart *const uart = priv->regs;
 | |
| 
 | |
| 	return _sti_asc_serial_setbrg(uart, baudrate);
 | |
| }
 | |
| 
 | |
| /* blocking function, that returns next char */
 | |
| static int sti_asc_serial_getc(struct udevice *dev)
 | |
| {
 | |
| 	struct sti_asc_serial *priv = dev_get_priv(dev);
 | |
| 	struct sti_asc_uart *const uart = priv->regs;
 | |
| 
 | |
| 	/* polling wait: for a char to be read */
 | |
| 	if (!sti_asc_pending(dev, true))
 | |
| 		return -EAGAIN;
 | |
| 
 | |
| 	return readl(&uart->rxbuf);
 | |
| }
 | |
| 
 | |
| /* write write out a single char */
 | |
| static int sti_asc_serial_putc(struct udevice *dev, const char c)
 | |
| {
 | |
| 	struct sti_asc_serial *priv = dev_get_priv(dev);
 | |
| 	struct sti_asc_uart *const uart = priv->regs;
 | |
| 
 | |
| 	/* wait till safe to write next char */
 | |
| 	if (sti_asc_pending(dev, false))
 | |
| 		return -EAGAIN;
 | |
| 
 | |
| 	/* finally, write next char */
 | |
| 	writel(c, &uart->txbuf);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /* initialize the ASC */
 | |
| static int sti_asc_serial_probe(struct udevice *dev)
 | |
| {
 | |
| 	struct sti_asc_serial *priv = dev_get_priv(dev);
 | |
| 	unsigned long val;
 | |
| 	fdt_addr_t base;
 | |
| 
 | |
| 	base = devfdt_get_addr(dev);
 | |
| 	if (base == FDT_ADDR_T_NONE)
 | |
| 		return -EINVAL;
 | |
| 
 | |
| 	priv->regs = (struct sti_asc_uart *)base;
 | |
| 	sti_asc_serial_setbrg(dev, gd->baudrate);
 | |
| 
 | |
| 	/*
 | |
| 	 * build up the value to be written to CONTROL
 | |
| 	 * set character length, bit stop number, odd parity
 | |
| 	 */
 | |
| 	val = RXENABLE | RUN | MODE_8BIT | STOP_1BIT | PARITYODD;
 | |
| 	writel(val, &priv->regs->control);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static const struct dm_serial_ops sti_asc_serial_ops = {
 | |
| 	.putc = sti_asc_serial_putc,
 | |
| 	.pending = sti_asc_pending,
 | |
| 	.getc = sti_asc_serial_getc,
 | |
| 	.setbrg = sti_asc_serial_setbrg,
 | |
| };
 | |
| 
 | |
| static const struct udevice_id sti_serial_of_match[] = {
 | |
| 	{ .compatible = "st,asc" },
 | |
| 	{ }
 | |
| };
 | |
| 
 | |
| U_BOOT_DRIVER(serial_sti_asc) = {
 | |
| 	.name = "serial_sti_asc",
 | |
| 	.id = UCLASS_SERIAL,
 | |
| 	.of_match = sti_serial_of_match,
 | |
| 	.ops = &sti_asc_serial_ops,
 | |
| 	.probe = sti_asc_serial_probe,
 | |
| 	.priv_auto_alloc_size = sizeof(struct sti_asc_serial),
 | |
| 	.flags = DM_FLAG_PRE_RELOC,
 | |
| };
 | |
| 
 |