diff mbox

[edk2,6/6] ArmPlatformPkg: Fix PL011 Glitches.

Message ID 1464443656-12108-7-git-send-email-evan.lloyd@arm.com
State Superseded
Headers show

Commit Message

Evan Lloyd May 28, 2016, 1:54 p.m. UTC
From: Evan Lloyd <evan.lloyd@arm.com>


This change corrects 3 problems in the PL011 driver.
1. The TRM states "The UARTLCR_H, UARTIBRD, and UARTFBRD registers must
   not be changed:...when the UART is enabled"
2. The TRM (3.3.8) describes logic requiring the UART to be disabled and
   flushed before adjusting UARTCR.
3. Several redundant calls get made to PL011UartInitializePort, where
   the characteristics do not change, but updating the registers can
   cause glitches in the output stream.

The parameters are compared to the current state and no action taken if
no change of state is required.
Where an update is required, the specified logic is followed, and the
register updates only made when the UART is disabled.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>

Signed-off-by: Evan Lloyd <evan.lloyd@arm.com>

---
 ArmPlatformPkg/Drivers/PL011Uart/PL011Uart.c | 24 +++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

-- 
Guid("CE165669-3EF3-493F-B85D-6190EE5B9759")

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Comments

Ryan Harkin May 31, 2016, 3:12 p.m. UTC | #1
On 28 May 2016 at 14:54,  <evan.lloyd@arm.com> wrote:
> From: Evan Lloyd <evan.lloyd@arm.com>

>

> This change corrects 3 problems in the PL011 driver.

> 1. The TRM states "The UARTLCR_H, UARTIBRD, and UARTFBRD registers must

>    not be changed:...when the UART is enabled"

> 2. The TRM (3.3.8) describes logic requiring the UART to be disabled and

>    flushed before adjusting UARTCR.

> 3. Several redundant calls get made to PL011UartInitializePort, where

>    the characteristics do not change, but updating the registers can

>    cause glitches in the output stream.

>

> The parameters are compared to the current state and no action taken if

> no change of state is required.

> Where an update is required, the specified logic is followed, and the

> register updates only made when the UART is disabled.

>

> Contributed-under: TianoCore Contribution Agreement 1.0

> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>

> Signed-off-by: Evan Lloyd <evan.lloyd@arm.com>


Tested on Juno R2 and FVP Foundation and AEMv8 models.

Tested-by: Ryan Harkin <ryan.harkin@linaro.org>

Reviewed-by: Ryan Harkin <ryan.harkin@linaro.org>



> ---

>  ArmPlatformPkg/Drivers/PL011Uart/PL011Uart.c | 24 +++++++++++++++++++-

>  1 file changed, 23 insertions(+), 1 deletion(-)

>

> diff --git a/ArmPlatformPkg/Drivers/PL011Uart/PL011Uart.c b/ArmPlatformPkg/Drivers/PL011Uart/PL011Uart.c

> index 61b122a67ab7354714adb429e401126973ab6c8d..ec1abdd10c4ab2fdf59576af6eb3c92b8728d81a 100644

> --- a/ArmPlatformPkg/Drivers/PL011Uart/PL011Uart.c

> +++ b/ArmPlatformPkg/Drivers/PL011Uart/PL011Uart.c

> @@ -29,9 +29,11 @@

>  //

>  STATIC CONST UINT32 mInvalidControlBits = EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;

>

> -/*

> +/**

>

>    Initialise the serial port to the specified settings.

> +  The serial port is re-configured only if the specified settings

> +  are different from the current settings.

>    All unspecified settings will be set to the default values.

>

>    @param  UartBase                The base address of the serial device.

> @@ -188,6 +190,26 @@ PL011UartInitializePort (

>      Integer = Divisor >> FRACTION_PART_SIZE_IN_BITS;

>      Fractional = Divisor & FRACTION_PART_MASK;

>    }

> +

> +  //

> +  // If PL011 is already initialized, check the current settings

> +  // and re-initialize only if the settings are different.

> +  //

> +  if (((MmioRead32 (UartBase + UARTCR) & PL011_UARTCR_UARTEN) != 0) &&

> +       (MmioRead32 (UartBase + UARTLCR_H) == LineControl) &&

> +       (MmioRead32 (UartBase + UARTIBRD) == Integer) &&

> +       (MmioRead32 (UartBase + UARTFBRD) == Fractional)) {

> +    // Nothing to do - already initialized with correct attributes

> +    return RETURN_SUCCESS;

> +  }

> +

> +  // Wait for the end of transmission

> +  while ((MmioRead32 (UartBase + UARTFR) & PL011_UARTFR_TXFE) == 0);

> +

> +  // Disable UART: "The UARTLCR_H, UARTIBRD, and UARTFBRD registers must not be changed

> +  // when the UART is enabled"

> +  MmioWrite32 (UartBase + UARTCR, 0);

> +

>    // Set Baud Rate Registers

>    MmioWrite32 (UartBase + UARTIBRD, Integer);

>    MmioWrite32 (UartBase + UARTFBRD, Fractional);

> --

> Guid("CE165669-3EF3-493F-B85D-6190EE5B9759")

>

> _______________________________________________

> edk2-devel mailing list

> edk2-devel@lists.01.org

> https://lists.01.org/mailman/listinfo/edk2-devel

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
diff mbox

Patch

diff --git a/ArmPlatformPkg/Drivers/PL011Uart/PL011Uart.c b/ArmPlatformPkg/Drivers/PL011Uart/PL011Uart.c
index 61b122a67ab7354714adb429e401126973ab6c8d..ec1abdd10c4ab2fdf59576af6eb3c92b8728d81a 100644
--- a/ArmPlatformPkg/Drivers/PL011Uart/PL011Uart.c
+++ b/ArmPlatformPkg/Drivers/PL011Uart/PL011Uart.c
@@ -29,9 +29,11 @@ 
 //
 STATIC CONST UINT32 mInvalidControlBits = EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
 
-/*
+/**
 
   Initialise the serial port to the specified settings.
+  The serial port is re-configured only if the specified settings
+  are different from the current settings.
   All unspecified settings will be set to the default values.
 
   @param  UartBase                The base address of the serial device.
@@ -188,6 +190,26 @@  PL011UartInitializePort (
     Integer = Divisor >> FRACTION_PART_SIZE_IN_BITS;
     Fractional = Divisor & FRACTION_PART_MASK;
   }
+
+  //
+  // If PL011 is already initialized, check the current settings
+  // and re-initialize only if the settings are different.
+  //
+  if (((MmioRead32 (UartBase + UARTCR) & PL011_UARTCR_UARTEN) != 0) &&
+       (MmioRead32 (UartBase + UARTLCR_H) == LineControl) &&
+       (MmioRead32 (UartBase + UARTIBRD) == Integer) &&
+       (MmioRead32 (UartBase + UARTFBRD) == Fractional)) {
+    // Nothing to do - already initialized with correct attributes
+    return RETURN_SUCCESS;
+  }
+
+  // Wait for the end of transmission
+  while ((MmioRead32 (UartBase + UARTFR) & PL011_UARTFR_TXFE) == 0);
+
+  // Disable UART: "The UARTLCR_H, UARTIBRD, and UARTFBRD registers must not be changed
+  // when the UART is enabled"
+  MmioWrite32 (UartBase + UARTCR, 0);
+
   // Set Baud Rate Registers
   MmioWrite32 (UartBase + UARTIBRD, Integer);
   MmioWrite32 (UartBase + UARTFBRD, Fractional);