|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v1 2/4] xen/arm: drivers: scif: Add support for SCIFA compatible UARTs
On Tue, Aug 7, 2018 at 4:43 PM, Julien Grall <julien.grall@xxxxxxx> wrote:
> Hi Oleksandr,
Hi, Julien
>
>
> On 06/08/18 19:35, Oleksandr Tyshchenko wrote:
>>
>> From: Oleksandr Tyshchenko <oleksandr_tyshchenko@xxxxxxxx>
>>
>> Extend existing driver to be able to handle SCIFA interface as well.
>> SCIF and SCIFA have lot in common, though SCIFA has different
>> offsets and bits for some registers.
>>
>> Use compatible string to recognize what interface is present
>> on a target board.
>>
>> Signed-off-by: Oleksandr Tyshchenko <oleksandr_tyshchenko@xxxxxxxx>
>> CC: Stefano Stabellini <sstabellini@xxxxxxxxxx>
>> CC: Julien Grall <julien.grall@xxxxxxx>
>> ---
>> xen/drivers/char/scif-uart.c | 129
>> +++++++++++++++++++++++++++++++---------
>> xen/include/asm-arm/scif-uart.h | 44 ++++++++++++--
>> 2 files changed, 138 insertions(+), 35 deletions(-)
>>
>> diff --git a/xen/drivers/char/scif-uart.c b/xen/drivers/char/scif-uart.c
>> index 465fb34..d1eb713 100644
>> --- a/xen/drivers/char/scif-uart.c
>> +++ b/xen/drivers/char/scif-uart.c
>> @@ -1,7 +1,7 @@
>> /*
>> * xen/drivers/char/scif-uart.c
>> *
>> - * Driver for SCIF (Serial communication interface with FIFO)
>> + * Driver for SCIF(A) (Serial communication interface with FIFO (A))
>> * compatible UART.
>> *
>> * Oleksandr Tyshchenko <oleksandr.tyshchenko@xxxxxxxxxxxxxxx>
>> @@ -40,8 +40,57 @@ static struct scif_uart {
>> char __iomem *regs;
>> struct irqaction irqaction;
>> struct vuart_info vuart;
>> + const struct port_params *params;
>> } scif_com = {0};
>> +enum
>
>
> Should not this enum has a name?
I think, it should.
>
>
>> +{
>> + SCIF_PORT,
>> + SCIFA_PORT,
>> + NR_PORTS,
>> +};
>> +
>> +struct port_params
>> +{
>> + unsigned int status_reg;
>> + unsigned int tx_fifo_reg;
>> + unsigned int rx_fifo_reg;
>> + unsigned int overrun_reg;
>> + unsigned int overrun_mask;
>> + unsigned int error_mask;
>> + unsigned int irq_flags;
>> + unsigned int fifo_size;
>> +};
>> +
>> +static const struct port_params port_params[NR_PORTS] =
>> +{
>> + [SCIF_PORT] =
>> + {
>> + .status_reg = SCIF_SCFSR,
>> + .tx_fifo_reg = SCIF_SCFTDR,
>> + .rx_fifo_reg = SCIF_SCFRDR,
>> + .overrun_reg = SCIF_SCLSR,
>> + .overrun_mask = SCLSR_ORER,
>> + .error_mask = SCFSR_PER | SCFSR_FER | SCFSR_BRK | SCFSR_ER,
>> + .irq_flags = SCSCR_RIE | SCSCR_TIE | SCSCR_REIE,
>> + .fifo_size = 16,
>> + },
>> +
>> + [SCIFA_PORT] =
>> + {
>> + .status_reg = SCIFA_SCASSR,
>> + .tx_fifo_reg = SCIFA_SCAFTDR,
>> + .rx_fifo_reg = SCIFA_SCAFRDR,
>> + .overrun_reg = SCIFA_SCASSR,
>> + .overrun_mask = SCASSR_ORER,
>> + .error_mask = SCASSR_PER | SCASSR_FER | SCASSR_BRK | SCASSR_ER
>> |
>> + SCASSR_ORER,
>> + .irq_flags = SCASCR_RIE | SCASCR_TIE | SCASCR_DRIE |
>> SCASCR_ERIE |
>> + SCASCR_BRIE,
>> + .fifo_size = 64,
>> + },
>> +};
>> +
>> static void scif_uart_interrupt(int irq, void *data, struct
>> cpu_user_regs *regs)
>> {
>> struct serial_port *port = data;
>> @@ -49,7 +98,7 @@ static void scif_uart_interrupt(int irq, void *data,
>> struct cpu_user_regs *regs)
>> uint16_t status, ctrl;
>> ctrl = scif_readw(uart, SCIF_SCSCR);
>> - status = scif_readw(uart, SCIF_SCFSR) & ~SCFSR_TEND;
>> + status = scif_readw(uart, uart->params->status_reg) & ~SCFSR_TEND;
>
>
> I would prefer if you introduce a local variable for the params. This would
> avoid to write uart->params everywhere.
Agree. Do you want me to use this local variable only in interrupt
handler or everywhere in a file where uart->params is used?
>
>
>> /* Ignore next flag if TX Interrupt is disabled */
>> if ( !(ctrl & SCSCR_TIE) )
>> status &= ~SCFSR_TDFE;
>> @@ -65,13 +114,19 @@ static void scif_uart_interrupt(int irq, void *data,
>> struct cpu_user_regs *regs)
>> serial_rx_interrupt(port, regs);
>> /* Error Interrupt */
>> - if ( status & SCIF_ERRORS )
>> - scif_writew(uart, SCIF_SCFSR, ~SCIF_ERRORS);
>> - if ( scif_readw(uart, SCIF_SCLSR) & SCLSR_ORER )
>> - scif_writew(uart, SCIF_SCLSR, 0);
>> + if ( status & uart->params->error_mask )
>> + scif_writew(uart, uart->params->status_reg,
>> + ~uart->params->error_mask);
>> + if ( uart->params->overrun_reg != uart->params->status_reg )
>> + {
>> + if ( scif_readw(uart, uart->params->overrun_reg) &
>> + uart->params->overrun_mask )
>> + scif_writew(uart, uart->params->overrun_reg,
>> + ~uart->params->overrun_mask);
>> + }
>> ctrl = scif_readw(uart, SCIF_SCSCR);
>> - status = scif_readw(uart, SCIF_SCFSR) & ~SCFSR_TEND;
>> + status = scif_readw(uart, uart->params->status_reg) &
>> ~SCFSR_TEND;
>> /* Ignore next flag if TX Interrupt is disabled */
>> if ( !(ctrl & SCSCR_TIE) )
>> status &= ~SCFSR_TDFE;
>> @@ -86,7 +141,7 @@ static void __init scif_uart_init_preirq(struct
>> serial_port *port)
>> * Wait until last bit has been transmitted. This is needed for a
>> smooth
>> * transition when we come from early printk
>> */
>> - while ( !(scif_readw(uart, SCIF_SCFSR) & SCFSR_TEND) );
>> + while ( !(scif_readw(uart, uart->params->status_reg) & SCFSR_TEND) );
>> /* Disable TX/RX parts and all interrupts */
>> scif_writew(uart, SCIF_SCSCR, 0);
>> @@ -95,10 +150,13 @@ static void __init scif_uart_init_preirq(struct
>> serial_port *port)
>> scif_writew(uart, SCIF_SCFCR, SCFCR_RFRST | SCFCR_TFRST);
>> /* Clear all errors and flags */
>> - scif_readw(uart, SCIF_SCFSR);
>> - scif_writew(uart, SCIF_SCFSR, 0);
>> - scif_readw(uart, SCIF_SCLSR);
>> - scif_writew(uart, SCIF_SCLSR, 0);
>> + scif_readw(uart, uart->params->status_reg);
>> + scif_writew(uart, uart->params->status_reg, 0);
>> + if ( uart->params->overrun_reg != uart->params->status_reg )
>
>
> I don't think there is any harm to reset the registers twice when
> overrun_reg != status_reg.
Agree.
>
>
>> + {
>> + scif_readw(uart, uart->params->overrun_reg);
>> + scif_writew(uart, uart->params->overrun_reg, 0);
>> + }
>> /* Setup trigger level for TX/RX FIFOs */
>> scif_writew(uart, SCIF_SCFCR, SCFCR_RTRG11 | SCFCR_TTRG11);
>> @@ -122,14 +180,19 @@ static void __init scif_uart_init_postirq(struct
>> serial_port *port)
>> uart->irq);
>> /* Clear all errors */
>> - if ( scif_readw(uart, SCIF_SCFSR) & SCIF_ERRORS )
>> - scif_writew(uart, SCIF_SCFSR, ~SCIF_ERRORS);
>> - if ( scif_readw(uart, SCIF_SCLSR) & SCLSR_ORER )
>> - scif_writew(uart, SCIF_SCLSR, 0);
>> + if ( scif_readw(uart, uart->params->status_reg) &
>> uart->params->error_mask )
>> + scif_writew(uart, uart->params->status_reg,
>> ~uart->params->error_mask);
>> + if ( uart->params->overrun_reg != uart->params->status_reg )
>> + {
>> + if ( scif_readw(uart, uart->params->overrun_reg) &
>> + uart->params->overrun_mask )
>> + scif_writew(uart, uart->params->overrun_reg,
>> + ~uart->params->overrun_mask);
>> + }
>> /* Enable TX/RX and Error Interrupts */
>> scif_writew(uart, SCIF_SCSCR, scif_readw(uart, SCIF_SCSCR) |
>> - SCSCR_TIE | SCSCR_RIE | SCSCR_REIE);
>> + uart->params->irq_flags);
>
>
> The indentation looks wrong here.
Will correct.
>
>
>> }
>> static void scif_uart_suspend(struct serial_port *port)
>> @@ -148,24 +211,25 @@ static int scif_uart_tx_ready(struct serial_port
>> *port)
>> uint16_t cnt;
>> /* Check for empty space in TX FIFO */
>> - if ( !(scif_readw(uart, SCIF_SCFSR) & SCFSR_TDFE) )
>> + if ( !(scif_readw(uart, uart->params->status_reg) & SCFSR_TDFE) )
>> return 0;
>> /* Check number of data bytes stored in TX FIFO */
>> cnt = scif_readw(uart, SCIF_SCFDR) >> 8;
>> - ASSERT( cnt >= 0 && cnt <= SCIF_FIFO_MAX_SIZE );
>> + ASSERT( cnt >= 0 && cnt <= uart->params->fifo_size );
>> - return (SCIF_FIFO_MAX_SIZE - cnt);
>> + return (uart->params->fifo_size - cnt);
>> }
>> static void scif_uart_putc(struct serial_port *port, char c)
>> {
>> struct scif_uart *uart = port->uart;
>> - scif_writeb(uart, SCIF_SCFTDR, c);
>> + scif_writeb(uart, uart->params->tx_fifo_reg, c);
>> /* Clear required TX flags */
>> - scif_writew(uart, SCIF_SCFSR, scif_readw(uart, SCIF_SCFSR) &
>> - ~(SCFSR_TEND | SCFSR_TDFE));
>> + scif_writew(uart, uart->params->status_reg,
>> + scif_readw(uart, uart->params->status_reg) &
>> + ~(SCFSR_TEND | SCFSR_TDFE));
>> }
>> static int scif_uart_getc(struct serial_port *port, char *pc)
>> @@ -173,15 +237,16 @@ static int scif_uart_getc(struct serial_port *port,
>> char *pc)
>> struct scif_uart *uart = port->uart;
>> /* Check for available data bytes in RX FIFO */
>> - if ( !(scif_readw(uart, SCIF_SCFSR) & (SCFSR_RDF | SCFSR_DR)) )
>> + if ( !(scif_readw(uart, uart->params->status_reg) &
>> + (SCFSR_RDF | SCFSR_DR)) )
>> return 0;
>> - *pc = scif_readb(uart, SCIF_SCFRDR);
>> + *pc = scif_readb(uart, uart->params->rx_fifo_reg);
>> /* dummy read */
>> - scif_readw(uart, SCIF_SCFSR);
>> + scif_readw(uart, uart->params->status_reg);
>> /* Clear required RX flags */
>> - scif_writew(uart, SCIF_SCFSR, ~(SCFSR_RDF | SCFSR_DR));
>> + scif_writew(uart, uart->params->status_reg, ~(SCFSR_RDF | SCFSR_DR));
>> return 1;
>> }
>> @@ -265,10 +330,15 @@ static int __init scif_uart_init(struct
>> dt_device_node *dev,
>> return -ENOMEM;
>> }
>> + if ( dt_device_is_compatible(dev, "renesas,scifa") )
>> + uart->params = &port_params[SCIFA_PORT];
>> + else
>> + uart->params = &port_params[SCIF_PORT];
>
>
> You can use the field .data in dt_device_match to store specific data and
> then use dt_match_node to find the correct node.
I understand. Will change.
>
>
>> +
>> uart->vuart.base_addr = addr;
>> uart->vuart.size = size;
>> - uart->vuart.data_off = SCIF_SCFTDR;
>> - uart->vuart.status_off = SCIF_SCFSR;
>> + uart->vuart.data_off = uart->params->tx_fifo_reg;
>> + uart->vuart.status_off = uart->params->status_reg;
>> uart->vuart.status = SCFSR_TDFE;
>> /* Register with generic serial driver */
>> @@ -282,6 +352,7 @@ static int __init scif_uart_init(struct dt_device_node
>> *dev,
>> static const struct dt_device_match scif_uart_dt_match[] __initconst =
>> {
>> DT_MATCH_COMPATIBLE("renesas,scif"),
>> + DT_MATCH_COMPATIBLE("renesas,scifa"),
>> { /* sentinel */ },
>> };
>> diff --git a/xen/include/asm-arm/scif-uart.h
>> b/xen/include/asm-arm/scif-uart.h
>> index 8137850..bce3404 100644
>> --- a/xen/include/asm-arm/scif-uart.h
>> +++ b/xen/include/asm-arm/scif-uart.h
>> @@ -2,7 +2,7 @@
>> * xen/include/asm-arm/scif-uart.h
>> *
>> * Common constant definition between early printk and the UART driver
>> - * for the SCIF compatible UART.
>> + * for the SCIF(A) compatible UART.
>> *
>> * Oleksandr Tyshchenko <oleksandr.tyshchenko@xxxxxxxxxxxxxxx>
>> * Copyright (C) 2014, Globallogic.
>> @@ -21,9 +21,7 @@
>> #ifndef __ASM_ARM_SCIF_UART_H
>> #define __ASM_ARM_SCIF_UART_H
>> -#define SCIF_FIFO_MAX_SIZE 16
>> -
>> -/* Register offsets */
>> +/* Register offsets (SCIF) */
>> #define SCIF_SCSMR (0x00) /* Serial mode register */
>> #define SCIF_SCBRR (0x04) /* Bit rate register */
>> #define SCIF_SCSCR (0x08) /* Serial control register */
>> @@ -57,8 +55,6 @@
>> #define SCFSR_RDF (1 << 1) /* Receive FIFO Data Full */
>> #define SCFSR_DR (1 << 0) /* Receive Data Ready */
>> -#define SCIF_ERRORS (SCFSR_PER | SCFSR_FER | SCFSR_ER | SCFSR_BRK)
>> -
>> /* Line Status Register (SCLSR) */
>> #define SCLSR_TO (1 << 2) /* Timeout */
>> #define SCLSR_ORER (1 << 0) /* Overrun Error */
>> @@ -83,6 +79,42 @@
>> #define SCFCR_TTRG10 (SCFCR_TTRG1)
>> #define SCFCR_TTRG11 (SCFCR_TTRG1 | SCFCR_TTRG0)
>> +/* Register offsets (SCIFA) */
>> +#define SCIFA_SCASMR (0x00) /* Serial mode register */
>> +#define SCIFA_SCABRR (0x04) /* Bit rate register */
>> +#define SCIFA_SCASCR (0x08) /* Serial control register */
>> +#define SCIFA_SCATDSR (0x0C) /* Transmit data stop register */
>> +#define SCIFA_SCAFER (0x10) /* FIFO error count register */
>> +#define SCIFA_SCASSR (0x14) /* Serial status register */
>> +#define SCIFA_SCAFCR (0x18) /* FIFO control register */
>> +#define SCIFA_SCAFDR (0x1C) /* FIFO data count register */
>> +#define SCIFA_SCAFTDR (0x20) /* Transmit FIFO data register */
>> +#define SCIFA_SCAFRDR (0x24) /* Receive FIFO data register */
>> +#define SCIFA_SCAPCR (0x30) /* Serial port control register */
>> +#define SCIFA_SCAPDR (0x34) /* Serial port data register */
>> +
>> +/* Serial Control Register (SCASCR) */
>> +#define SCASCR_ERIE (1 << 10) /* Receive Error Interrupt Enable */
>> +#define SCASCR_BRIE (1 << 9) /* Break Interrupt Enable */
>> +#define SCASCR_DRIE (1 << 8) /* Receive Data Ready Interrupt
>> Enable */
>> +#define SCASCR_TIE (1 << 7) /* Transmit Interrupt Enable */
>> +#define SCASCR_RIE (1 << 6) /* Receive Interrupt Enable */
>> +#define SCASCR_TE (1 << 5) /* Transmit Enable */
>> +#define SCASCR_RE (1 << 4) /* Receive Enable */
>> +#define SCASCR_CKE0 (1 << 0) /* Clock Enable 0 */
>> +
>> +/* Serial Status Register (SCASSR) */
>> +#define SCASSR_ORER (1 << 9) /* Overrun Error */
>> +#define SCASSR_TSF (1 << 8) /* Transmit Data Stop */
>> +#define SCASSR_ER (1 << 7) /* Receive Error */
>> +#define SCASSR_TEND (1 << 6) /* Transmission End */
>> +#define SCASSR_TDFE (1 << 5) /* Transmit FIFO Data Empty */
>> +#define SCASSR_BRK (1 << 4) /* Break Detect */
>> +#define SCASSR_FER (1 << 3) /* Framing Error */
>> +#define SCASSR_PER (1 << 2) /* Parity Error */
>> +#define SCASSR_RDF (1 << 1) /* Receive FIFO Data Full */
>> +#define SCASSR_DR (1 << 0) /* Receive Data Ready */
>> +
>> #endif /* __ASM_ARM_SCIF_UART_H */
>> /*
>>
>
> Cheers,
>
> --
> Julien Grall
--
Regards,
Oleksandr Tyshchenko
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |