First, you can refer that link for example RSU code with UART: (https://community.intel.com/t5/FPGA-SoC-And-CPLD-Boards-And/Max1000-Remote-System-Upgrade-via-SPI/m-p/1368963/highlight/true#M22012).
Second, you can use this UART core: (https://opencores.org/projects/simple_uart_for_fpga). It is very simple, easy to use and you can control everything.
Third, in fact RSU logic without Nios is not that complex, but lack of documentation complicate it. As you know there are 2 images in MAX10 devices. 2 CFMs for image2 and 1 CFM for image1. Normally if you didn't do contrary, device begins with image1. You can change this with driving config_sel pin physically. If there is no image of one of them, or the image is broken, device begins with solid one. If both of them is broken or not programmed, device cannot begin. Yes you can clear and reprogram the working image when its working, but I think you have to still use the dual IP core. Because device not restarts itself when new CFM image loaded. You do it with IP. Maybe manual power on-off can work either, but in that case of "Remote" System Upgrade, you don't want to do it.