[U-Boot] [PATCH] dm: serial: Add .pre_probe() function to to wait for previous transmission end

Dr. Philipp Tomsich philipp.tomsich at theobroma-systems.com
Thu Oct 26 22:19:05 UTC 2017


> On 27 Oct 2017, at 00:13, Lukasz Majewski <lukma at denx.de> wrote:
> 
> It may happen that the serial IP block is performing some ongoing
> transmission (started at e.g. board_init()) when the serial "probe" is
> called.
> 
> As a result the serial port IP block is reset, so transmitted data is
> corrupted:
> 
>    I2C:   ready
>    DRAM:  1 GiB
>    jSS('HH��SL_SDHC: 04 rev 0x0
> 
> This patch prevents from this situation, by defining pre_probe() callback
> in which we wait till the TX buffer is empty (from previous transmission):
> 
>    I2C:   ready
>    DRAM:  1 GiB
>    ID:    unit type 0x4 rev 0x0
> 
> All defined ->pending callbacks at ./drivers/serial are non blocking
> - just simple reading from registers and testing flags. Hence, it should
> be enough to not use any timeout from timer.
> One shall also note that we enable console very early - not all timers
> may be ready for work - adding timeout here would impose implicit
> dependency that timers are setup before serial.

Given that this is effectively a busy polling loop, why can’t this be done
from the probe-function of serial drivers that require this functionality?

> 
> 
> Signed-off-by: Lukasz Majewski <lukma at denx.de>
> ---
> 
> drivers/serial/serial-uclass.c | 20 ++++++++++++++++++++
> 1 file changed, 20 insertions(+)
> 
> diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
> index 2e5116f..5e6964d 100644
> --- a/drivers/serial/serial-uclass.c
> +++ b/drivers/serial/serial-uclass.c
> @@ -420,10 +420,30 @@ static int serial_pre_remove(struct udevice *dev)
> 	return 0;
> }
> 
> +static int serial_pre_probe(struct udevice *dev)
> +{
> +	struct dm_serial_ops *ops = serial_get_ops(dev);
> +	int ret = 0;
> +
> +	/*
> +	 * Wait for any ongoing transmission to finish - for example
> +	 * from pre-relocation enabled UART
> +	 */
> +	if (ops && ops->pending)
> +		do {
> +			ret = ops->pending(dev, false);
> +			if (ret < 0)
> +				break;
> +		} while (ret > 0);
> +
> +	return ret;
> +}
> +
> UCLASS_DRIVER(serial) = {
> 	.id		= UCLASS_SERIAL,
> 	.name		= "serial",
> 	.flags		= DM_UC_FLAG_SEQ_ALIAS,
> +	.pre_probe	= serial_pre_probe,
> 	.post_probe	= serial_post_probe,
> 	.pre_remove	= serial_pre_remove,
> 	.per_device_auto_alloc_size = sizeof(struct serial_dev_priv),
> -- 
> 2.1.4
> 



More information about the U-Boot mailing list