Change kernel console cmdline to use UART1 (ttyTHS0)

I modified flash.sh and have this cmdline:

Kernel command line: root=/dev/mmcblk0p1 rw rootwait console=ttyTHS0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0 rootfstype=ext4 video=tegrafb no_console_suspend=1 earlycon=tegra_comb_uart,mmio32,0x0c168000 gpt usbcore.old_scheme_first=1 tegraid=19.1.2.0.0 maxcpus=8 boot.slot_suffix= boot.ratchetvalues=0.2.2 vpr=0x8000000@0xf0000000 sdhci_tegra.en_boot_part_access=1

However, I still see nothing on UART1 when connected to J30 to indicate that the kernel console is actually running there. Are there other changes I would need to make for this to work besides the cmdline?

I can only give partial information, this will be incomplete.

The kernel command line is indeed the correct place to name the serial console for after Linux has booted. U-Boot has its own specification.

The latest Xavier releases go directly from CBoot to Linux without U-Boot, but much of this is the same across recent Jetsons with minor differences if you look at the next paragraphs.

The “/dev/ttyS0” is the default. Note that “/dev/ttyTHS0” is the same hardware, but a different DMA-capable driver. U-Boot only supports the older “/dev/ttyS0” port due to the driver it contains. In the default configuration the reason the kernel command line uses “/dev/ttyS0” is to provide continuity of serial console from U-Boot stage to Linux kernel stage without having to reload a different driver. There may be other restrictions which make the older driver without DMA desirable even on a different port for the Linux kernel (such as “/dev/ttyS1”).

The command line and boot parameters used to be added only via the extlinux.conf configuration file. Now this is done instead mostly by the device tree (the “chosen/bootargs” entry), and earlier boot stages pass this one (perhaps with minor edits) to Linux. Since Xavier is the first of the Jetsons to not use U-Boot the device tree is the only place to make such changes. If extlinux.conf was used, then there would be a problem. Did you change bootargs via flashing a device tree? Is the change reflected in the following two locations:

cat /proc/cmdline
cat /proc/device-tree/chosen/bootargs

The J30 complicates things. The device tree will be different in a J30, and so although the above still applies to it the device tree changes may be different…you would be editing the J90 device tree “chosen/bootargs” the same as before, but if you used the stock Jetson dev kit tree without the J90 BSP, then odd things might occur.

Someone else may be able to give better details on actual changes for the J90.

Thank you for the help!

Sorry if I wasn’t clear - I meant that I plugged a USB-Serial adapter to UART1 on the J30 header of the dev kit. Same adapter works fine when /dev/ttyTHS0 is running getty, so I know its not my setup.

By default, I get ttyTCU0 as the console. I will try changing to ttyS0.

Yes my changes are reflected in /proc/cmdline and the device tree. Probably the issue is as you said ttyTHS0 not usable by the bootloader. As I said, I will try ttyS0 instead.

Unfortunately, ttyS0 made no difference - still nothing, though the DTB and cmdline look correct to me:

$ cat /proc/cmdline
root=/dev/mmcblk0p1 rw rootwait console=ttyS0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0 rootfstype=ext4 video=tegrafb no_console_suspend=1 earlycon=tegra_comb_uart,mmio32,0x0c168000 gpt usbcore.old_scheme_first=1 tegraid=19.1.2.0.0 maxcpus=8 boot.slot_suffix= boot.ratchetvalues=0.2.2 vpr=0x8000000@0xf0000000 sdhci_tegra.en_boot_part_access=1

$ cat /proc/device-tree/chosen/bootargs
root=/dev/mmcblk0p1 rw rootwait console=ttyS0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0 rootfstype=ext4 video=tegrafb no_console_suspend=1 earlycon=tegra_comb_uart,mmio32,0x0c168000 gpt usbcore.old_scheme_first=1 tegraid=19.1.2.0.0 maxcpus=8 boot.slot_suffix= boot.ratchetvalues=0.2.2 vpr=0x8000000@0xf0000000 sdhci_tegra.en_boot_part_access=1 airr@tegra-ubuntu:~$

If you are trying to use serial console on the Xavier, then the default is “/dev/ttyTCU0”. This actually goes to an FTDI USB serial UART on the micro-USB connector (the Xavier does not need an FTDI driver here, but the host PC side does). Are you trying to change to a new UART?

Default for serial console in cmdline: “console=ttyTCU0,115200n8”.

Yes I am trying to change the default from ttyTCU0 to ttyTHS0 (or ttyS0, whichever is UART1 on the expansion header).

I then am hooking up an adapter such as https://www.amazon.com/gp/product/B00DJUHGHI/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1

Adapter works fine on UART1, which normally is running a login prompt with getty. However, I want the main kernel console to go to UART1, not just getty. Need to be able to see the kernel booting up on that UART.

Can confirm that if I change the serial port to use tegra20-uart instead of tegra186-hsuart, and cmdline is console=ttys0,115200n8 I can see output during boot - but it is garbage (almost as if baud rate doesn’t match, but it does).

I think the tegra20-uart driver doesn’t quite work correctly, since even if I do a simple test with it I get garbage output (such as echoing to it, still is garbage, even if I stty to make sure baud rates all match). So which driver can I use and what config does it need to make a UART work as kernel console?

I have not made this change so someone else may need to comment, but the compatible entry of “tegra186-hsuart” versus “tegra20-uart” is a distinction of whether the DMA-capable driver or non-DMA drivers are compatible with the port. By having “compatible” list both it implies both drivers could be used (compatibility does not pick which driver loads, it only says the driver should work) on a port (and indeed they are both compatible with that hardware), but only one should be used at a time. I don’t know if there was perhaps a mixture of switching back and forth between drivers (in which case I couldn’t predict the results).

Either way, the hsuart has never been used as a serial console in the past…serial console has always been used (meaning tested) with the regular driver. I suggest access via the “ttyS#” syntax (and the non-DMA “tegra20-uart” in device tree) and skipping the “ttyTHS#” syntax. In boot stages prior to the kernel all of this serial port content was passed via the non-DMA driver.

Understood all that, and it’s what I did. However, tegra20-uart driver seems fundamentally broken. No matter what I do I get garbage when trying to communicate using it.

I couldn’t tell you what is wrong, but almost always garbage is one of:

  1. Incorrect speed settings.
  2. Long wiring without twisted pair losing to noise (I like using ethernet cable with shielding and twisted pairs for UARTs).
  3. Incompatible voltage settings between the two UARTs, e.g., a 5V level talking to a 3.3V level (Xavier is 3.3V).
  4. Other incorrect settings, e.g., stop bits being off will consider the wrong bits for a character.

This accepted answer is not actually correct as far as I have been able to tell. If you modify the tegra194-soc-uart.dtsi (and there is also one more, forget the exact name but if you grep for serial you will find it, since UART1 is overloaded there) file and change UART1’s entry to be ONLY tegra20-uart, you will find that ttyS1 does not function properly at any speed or baud rate settings using the pins on the dev kit.

I can confirm on a custom carrier board, I get the same behavior, ttyS1 just gives nonsense using tegra20-uart.

HOWEVER - UART2 works completely FINE using tegra20-uart driver. My custom carrier board has this and UART3 broken out, so I am using UART2 as my kernel console now with no issue. It is quite bizarre but apparently somehow UART1 isn’t compatible with tegra20-uart, or perhaps needs further DTS changes than the other ports.

When a UART is told it is compatible with multiple drivers, then only one is picked at a time (else there will be some bad undefined behavior). If you have switched “compatible” to remove all but one, and then the UART doesn’t work, it sounds as if somewhere during boot something is still trying to force the loading of the other driver and because of the device tree now lacking that driver the driver is being denied. So it may still be a case of mixing drivers…the ttyS# syntax should work if that is the “compatible” entry, and if that driver was loaded.

To emphasize, I have not tried to provide an alternate serial port on Xavier before. There may be other details I do not know of, but the boot stage will have loaded one driver, and the Linux kernel should be bound to the same driver for continuity of service as boot transfers from one set of software to the next. U-Boot has no concept of the DMA-capable hsuart, but Xavier does not use U-Boot (at least not in this release). Xavier would have a driver built in to CBoot in order to accomplish any serial console prior to the Linux kernel, and although I strongly doubt there is a DMA-capable driver within CBoot it is possible NVIDIA added the DMA driver there. NVIDIA would have to answer which serial driver exists in CBoot.

I don’t believe this to be the case. With “only” tegra20-uart defined, I ONLY get ttyS0, indicating tegra186-hsuart wasn’t involved. Grepping through my device tree doesn’t show it anywhere related to UART1. I do believe there is some detail missing to be able to use UART1 with tegra20-uart.

Perhaps NVIDIA can answer…what driver is present for the serial UART in CBoot stage, and what is needed to move serial console from that UART to another?

Yes, and whatever it is, for some reason the process seems different for UART1 vs UART2. I can set UART2 to tegra20-uart and then the cmdline console to ttyS1 and it works fine for me. It is only UART1/ttyS0 that has the issue.