Documente Academic
Documente Profesional
Documente Cultură
Henry Choi
1. Since I am hosting the root file system on NFS, this module should NOT start until the NFS
rootfs is mounted. Modules seem to start AFTER NFS mounting.
2. To start/stop CPU1, this module should be probed and removed
NOTE TO SELF: after compiling modifying the kernel module and doing a module_install, the
modules still need to be copied to the NFS export!
When Xilinx made a marketing push to AMP (asymmetric multi-processing) a couple of years ago,
they put out (rather quietly) an application note ug978 that launched FreeRTOS on CPU1 from Linux
running on CPU0. I will try to use zynq_remoteproc module--the specialization of the generic Linux
remoteproc module--as verbatim as possible (<kernel>/drivers/remoteproc/zynq_remoteproc.c), to
launch my own bare metal C++ application on CPU1.
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 1/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
Firstly, the module has to be built. I added the following lines to my kernel defconfig:
CONFIG_RPMSG=y
CONFIG_REMOTEPROC=y
CONFIG_ZYNQ_REMOTEPROC=m
Next, the kernel has to be told about my desire to use the zynq_remoteproc driver, through DTS. I
added the following entry in zynq-zed-adv7511.dts:
remoteproc@1 {
compatible = "xlnx,zynq_remoteproc";
reg = < 0x1FE00000 0x200000 >;
interrupt-parent = <&gic>;
interrupts = < 0 37 0 0 38 0 >;
firmware = "cpu1app.elf";
ipino = <0>; //The only free ipino
vring0 = <2>;
vring1 = <3>;
};
Here, I am telling the kernel that I want to use the last 2 MB (out of 512 MB available on Zedboard)
of the RAM for the bare metal app running on CPU1. Please recall that the memory was declared in
zynq-zed.dtsi, which is included by zynq-zed-adv7511.dts:
memory {
device_type = "memory";
reg = <0x000000000 0x20000000>;
};
To constrain the Linux kernel to only 510 MB without having to change the above DTS entry, I add
"mem=510M" in the U-Boot kernel bootargs. Without it, the module cannot allocate coherent DMA
mapping for the last 2 MB because the following code in zynq_remoteproc probe will fail (I tried it
already):
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 2/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
In Xilinx document ug978, the CPU1 application was placed in the boot partition, right next to
BOOT.bin--which lives on my SD card. For convenience during development, I want to put the
application ELF file on the NFS export. Many Linux distributions seem to put firmware in
/lib/firmware, but according to the hard coded paths in fw_path string array
(<>/drivers/base/firmware_class.c), /lib/firmware/updates/ is also a possibility, as well as a
custom path specified in the "path" module parameter. This folder is conveniently accessible on my
NFS host, making development iteration easier.
I can just compile this DTS in bash and move the DTB into the TFTP download folder, because I am
downloading the kernel over TFTP:
~/work/zed/kernel/arch/arm/boot/dts$ ~/work/zed/kernel/scripts/dtc/dtc -I
dts -O dtb -o zynq-zed-adv7511.dtb zynq-zed-adv7511.dts
~/work/zed/kernel/arch/arm/boot/dts$ sudo mv zynq-zed-adv7511.dtb
/var/lib/tftpboot/
Of course, there is no cpu1app ELF file in /lib/firmware, BUT the modprobe fails for a different
reason if I ipino in DTS is anything other than 0:
Reading set_ipi_handler(), I realized that 0 (IPI_WAKEUP) is the only available IPI handler number,
so I changed DTS. I do NOT plan to use virtio, so I simply commented out anything related to vring
in zynq_remoteproc with CONFIG_ZYNQ_IPC #ifdef.
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 3/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
1. Create a standalone BSP specialized for AMP CPU1 (when creating the Xilinx BSP project in
xsdk, select ps_cortexa9_1 as the CPU). Since I did not install the FreeRTOS template, the
only OS choice I get is standalone--hence the project name "standalone_bsp_1".
2. Compile a ELF executable that targets CPU1 and depends on the BSP just created above, and
hard coded to some load address
Since the CPU1 BSP will NOT be used for FSBL, there is an opportunity to reduce the code size
(compared to the CPU0 BSP) by NOT selecting any libraries--such as xilffs or xilrsa, as I've done
below:
Since I am NOT interested in debugging the BSP, I have an opportunity to increase the optimization
level and remove the debug (-g) flag in the BSP setting. But this is important: USE_AMP=1
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 4/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
preprocessor define in the BSP setting (right click on the BSP project in Eclipse --> Board Support
Package settings) changes some BSP code from the default BSP):
#if USE_AMP==1
// /* In case of AMP, map virtual address 0x20000000 to 0x00000000 and
mark it as non-cacheable */
// ldr r3, =0x1ff /* 512 entries to cover 512MB DDR */
// ldr r0, =TblBase /* MMU Table address in memory */
// add r0, r0, #0x800 /* Address of entry in MMU table, for 0x20000000 */
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 5/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
For the application, I copy the xapp 1079 CPU1 application as a new project "cpu1app" and start
modifying. Besides the application logic itself, the linker script (lscript.ld) specifies where the
code/data sections will be placed in memory (DDR, to be specific, by CPU0--but that is not the
concern of the linker script). xapp1079 reserved 0x02000000 through 0x02ffffff (16 MB) for CPU1,
but as shown in the DTS above, I want to allocate CPU1 memory at 0x1FE00000. So I change the
ps7_ddr_0_S_AXI_BASEADDR location and size to in the linker script editor, like this:
MEMORY
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 6/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
{
ps7_ddr_0_S_AXI_BASEADDR : ORIGIN = 0x1fe00000, LENGTH = 0x200000
}
Since the linker places all sections into the DDR, there is no reason to even mention other on-chip
memory (BRAM at 0x0 and OCM at 0xFFFC0000). I don't know the correct stack and heap size yet,
so I'll just leave them alone (8 KB each).
The simplest app I can think of is a blinker. Recently, John McDougall introduced a sleep method
using CPU1's private timer (which seems to be called SCU timer--I don't yet see the connection to
the snoop control unit). John McDougall's code for initializing the SCU timer and calling a sleep on
it is in this download (in design/src/apps/app_cpu1/scu_sleep.[ch]). My main() simply calls the
SCU timer init and then sleep for 1 second over and over.
while(1) {
XGpioPs_WritePin(&Gpio, OUTPUT_PIN, 0x1);
for (Delay = 0; Delay < LED_DELAY; Delay++);
XGpioPs_WritePin(&Gpio, OUTPUT_PIN, 0x0);
for (Delay = 0; Delay < LED_DELAY; Delay++);
}
return XST_SUCCESS;
}
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 7/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
int main(void)
{
int Status;
XGpioPs_Config *ConfigPtr;
ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
Status = XGpioPs_CfgInitialize(&Gpio, ConfigPtr,
ConfigPtr->BaseAddr);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
Status = GpioOutputExample();
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
return XST_SUCCESS;
}
WITHOUT the USE_AMP=1 modifications I made to boot.S above, I can launch this program from
xsdk (Xilinx SW development IDE), and I can see the blinking LED.
xsdk builds the ELF file with ease, and I moved that file into a new folder /lib/firmware within the
NFS exported root for the target. When I rebooted Zedboard, I was greeted with what seems like a
minor success in dmesg output:
CPU1: shutdown
remoteproc0: 1fe00000.remoteproc is available
remoteproc0: Note: remoteproc is still under development and considered
experimental.
remoteproc0: THE BINARY FORMAT IS NOT YET FINALIZED, and backward
compatibility isn't yet guaranteed.
As dmesg suggests, Linux first shut down CPU1. Silently, it tries to load the firmware through this
chain: zynq_remoteproc_probe() --> rproc_add() --> rproc_add_virtio_devices() -->
request_firmware_nowait() --> INIT_WORK(&fw_work->work, request_firmware_work_func) -->
request_firmware_work_func() --> _request_firmware() --> fw_get_filesystem_firmware() --
> fw_read_file_contents(). request_firmware_work_func() should also do post-FW load work (like
booting the remote proc) through the fw_work->cont function pointer to rproc_fw_config_virtio(),
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 8/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
The debugger does NOT respond when CPU1 is halted (as in this case), so I had to rely on printk. I
came to appreciate the value of out-of-tree module compilation:
~/work/zed/kernel/drivers/remoteproc$ make -C
/mnt/work/zed/buildroot/output/build/linux-custom ARCH=arm M=`pwd` modules
.resource_table : {
__rtable_start = .;
*(.rtable)
__rtable_end = .;
} > ps7_ddr_0_S_AXI_BASEADDR
The C program can have the global data as the resource table content:
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 9/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
struct fw_rsc_carveout {
u32 type;//from struct fw_rsc_hdr
u32 da;
u32 pa;
u32 len;
u32 flags;
u32 reserved;
u8 name[32];
} __packed;
With this change, my program is copied to the correct location in the DRAM, and I can dynamically
start/stop Linux on CPU1 by probing and removig the module, like this:
# rmmod zynq_remoteproc
# modprobe kernel/drivers/remoteproc/zynq_remoteproc.ko
# modprobe kernel/drivers/rpmsg/virtio_rpmsg_bus.ko
But the module's probe does still NOT get called (note that I crossed CONFIG_RPMSG=y from my
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 10/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
defconfig above)! I could not figure out how to get the virtio device probed, and for that matter,
another determined engineer could not either, so I just added in a single-threaded work queue to
call rproc_boot after the firmware is loaded.
struct zynq_rproc_pdata {
struct irq_list mylist;
struct rproc *rproc;
u32 ipino;
#ifdef CONFIG_ZYNQ_IPC
u32 vring0;
u32 vring1;
#endif
u32 mem_start;
u32 mem_end;
//Need my own workqueue rather than a shared work queue because I will
block for completion
struct workqueue_struct* wq;
struct work_struct boot_work;
};
wait_for_completion(&rproc->firmware_loading_complete);
dev_info(&rproc->dev, "firmware_loading_complete\n");
err = rproc_boot(rproc);
if(err)
dev_err(&rproc->dev, "rproc_boot %d\n", err);
}
INIT_WORK(&local->boot_work, boot_cpu1);
local->wq = create_singlethread_workqueue("znq_remoteproc boot");
if(IS_ERR(local->wq)) {
dev_err(&pdev->dev, "create_singlethread_workqueue %ld\n",
PTR_ERR(local->wq));
goto rproc_fault;
}
queue_work(local->wq, &local->boot_work);
...
}
remoteproc0: firmware_loading_complete
remoteproc0: powering up 1fe00000.remoteproc
remoteproc0: Read /lib/firmware/cpu1app.elf 0
remoteproc0: firmware: direct-loading firmware cpu1app.elf
remoteproc0: assign_firmware_buf, flag 5 state 0
remoteproc0: Booting fw image cpu1app.elf, size 150445
zynq_remoteproc 1fe00000.remoteproc: iommu not found
remoteproc0: rsc: type 0
remoteproc0: phdr: type 1 da 0x1fe00000 memsz 0xd890 filesz 0x8058
remoteproc0: rproc_da_to_va 1fe00000 --> (null) remoteproc0:
rproc_da_to_va 1fe0800c --> (null)
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 12/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
I can also debug my app in xsdk JTAG debugger. This debugger stack trace is a proof that I can
running Linux on CPU0 and my bare metal application on CPU1:
rmmod zynq_remoteproc does not work; remove() method is not even getting called. As a result, I
cannot stop cpu1app; it just starts at the system bootup, and keeps running--which is OK for an
embedded application. Another approach would be to create another module that boots and stops
zynq_remoteproc, but I don't know how to get a handle to the existing zynq_remoteproc instance...
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 13/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
} else { // bring up
rproc_boot(rproc);
}
return count;
}
static ssize_t up_show(struct device *dev,
struct device_attribute *attr, char *buf) {
struct rproc *rproc = container_of(dev, struct rproc, dev);
return sprintf(buf, "%d\n", rproc->state);
}
static DEVICE_ATTR_RW(up);
# cat /sys/devices/1fe00000.remoteproc/remoteproc0/up
0
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 14/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
And the up file now reads 0, which means RPROC_RUNNING (and the LED is bliking!).
# cat /sys/devices/1fe00000.remoteproc/remoteproc0/up
2
To stop CPU1, I have to do 2 things in succession: write 0 to the "up" file, and then remove the
module:
# rmmod zynq_remoteproc
zynq_remoteproc 1fe00000.remoteproc: zynq_remoteproc_remove
zynq_remoteproc 1fe00000.remoteproc: Deleting the irq_list
remoteproc0: releasing 1fe00000.remoteproc
CPU1: Booted secondary processor
At this point, Linux has been restarted on the 2nd processor; if I do things in this way, I can restart
the app again by modprobing and then writing 1 to the "up" file again.
44 comments:
Just wanted to say thank you: your posts have been of invaluable help for my project, and especially
this one.
I have been able to follow your explanation and I now have a working modified remoteproc.
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 15/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
Did you understand why zynq_remoterproc doesn't work out of the box? I mean: how is the original
code supposed to operate in order to actually launch the code on CPU1? Without your clever
modifications, the original code seems just useless...
Also: do you know why we do have to explicitly add the resource table? With the lscript.ld I had, my
ELF already contained the desired address in a segment. It seems to be redundant to have to add the
rtable by hand in the C code, I am puzzled.
Small question: did you figure out how to use an arbitrary path to the ELF firmware without
modifying code?
Thanks again!
Reply
The "soc0" is because your DTS is newer than mine. When I upgrade the ADI kernel to the latest
(3.18), I got that as well.
I think the path can be specified in either DTS or modprobe argument, but haven't looked into it.
Do you mind sharing your usage of zynq_remoteproc? I haven't heard of anyone else besides me who
used AMP...
Reply
sometimes still in a cache somewhere at the instant where CPU1 was unstopped. Therefore CPU1
was basically executing whatever he saw at 0x00000000 instead of my jump code, about 1 time out
of 5. So while the mechanism is correct, I didn’t figure out how to flush the cache. I tried to tweak
cache in zynq settings, sync/flush/etc. all Linux caches I can think of, but without success. Other
peoples seem to have the exact same issue, and I eventually gave up.
Remoteproc is now working for me, but what I dislike in this architecture is that some piece of
information has to be repeated in several places, leading to potential issues and maintenance
overhead. For instance the address of my CPU1 code (your 1fe000000) is declared:
1) in lscript.ld (as DDR baseaddr)
2) in the “.rtable” declaration in my main.c
3) in boot.S of the BSP
4) in the remoteproc declaration inside DTS
5) implicitly by the “mem=” of kernel bootargs
6) in my user-space program in order to be able to find the “up” file…
The fact that the firmware name is hardcoded inside the DTS is also not very convenient in my
opinion… I would be happy to be able to launch an arbitrary ELF for testing purpose. And despite my
efforts I didn’t figure out how to specify an alternate path to it. I am using symlink now.
I feel that it could be possible to make things simpler and more compact… Maybe I’ll figure it out
how when I’ll become more familiar with all this.
Well, I’ll stop complaining, sorry, I guess you know all this ;-)
I am not the owner of the project I am working on, so I cannot disclose a lot of details. But basically
we have Software Defined Radio in the FPGA, real-time C++ bare-metal code on CPU1 (using a home-
made state-machine framework) for operating it, and a .Net mono app under Linux on CPU0 to
manage and give orders to CPU1 (via am hom-made message queue). I am thus calling “modprobe
remoteproc” from a C# application ;-)
Thanks again a lot for your hard work and for sharing it! Your solution is so far the only one that
works perfectly!
Reply
I've done pretty much everything in your blog post except modifying boot.S to modify the DDR cache
states. I'm running Linux in the upper 256MB of DDR RAM and my cpu1 app is using 32MB of the lower
256MB DDR RAM. I'm not sure how to modify boot.S to fit my usage (or if it's necessary to do so). I
would appreciate any advise you can give! Thanks.
Reply
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 17/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
Replies
Finally,if your application is really working OK (despite the KERN_ERR), I would personally
just move on and come back to this some other day, because life is short.
ps7_ddr_0: memory@0 {
device_type="memory";
reg = <0x10000000 0x10000000>;
}
back to
ps7_ddr_0: memory@0 {
device_type="memory";
reg = <0x0 0x20000000>;
}
would do the track, but Linux still only sees 256MB. It is "Ignoring memory below
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 18/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
I now have AMP configured as you do here (510M/2M), with the boot.S changes as well.
The KERN_ERR still occurs and cpu1app loads, but doesn't boot now:
It seems like the KERN_ERR occurs because these checks here fail:
https://github.com/Xilinx/linux-xlnx/blob/xlnx_3.14/lib/smp_processor_id.c#L14
And so it goes on to print the KERN_ERR. But I suspect it may not be entirely fatal
because it goes on to execute code that would have been executed had the KERN_ERR not
occur, plus in my first AMP configuration (256M/32M), cpul1app got loaded and apparently
booted despite the KERN_ERR (though it didn't toggle the LED as expected).
I also noticed my elf file size is 170599, but remoteproc reports a fw image size of 66576.
Does this size difference happen for you too? I am using Yocto to generate the kernel,
device tree and rootfs images. The cpu1app elf is in the rootfs at /lib/firmware and the
file size there is also the smaller 66576. I wonder if there's compression going on during
the rootfs image creation. Are you using PetaLinux or something else?
Anyway, sorry for polluting your blog with my progress. If you have the time and
inclination, I'd appreciate any help you can offer.
Please note that right now, I am always manually starting my cpu1app. I know I have to
run an init.rc script at some point, so I would be curious in learning what you have done. I
am sorry that for now, I am not going to roll up my sleeves on this, because I am trying to
make progress on my other problems (trying to figure out video DMA).
As for figuring out the kernel code line number, I use Eclipse, as I described in this article:
http://henryomd.blogspot.com/2014/10/ways-to-study-linux-kernel-and-driver.html
The remoteproc load failure (bad phdr) I was getting in reply dated May 20, 2015 at 3:41
PM was due to me forgetting to change the RAM address in one of the many places it
needs to be specified. In this case, in the resource table.
On the custom zynq board I'm using, there is one lone PS GPIO not connected to anything
that I might be able to get at though and I am considering doing exactly as you said at
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 21/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
this point. All of the other PS MIO pins are used for USB, ethernet, etc. But my cpu1app is
also driving PS UART0 now, and no activity there either (I set ps7_uart_0 as
compatible="invalid" in the device tree. Does that make Linux ignore it so it's free for
CPU1 to use?).
Anyway, I think CPU1 isn't able to read the cpu1app elf because of some MMU
misconfiguration or protection still in place. Would appreciate any thoughts you might
have on where to go with this.
I think got the same error you did, but I think it's expected: if you followed my (originally
John McDougall's code) CPU1 bootup code turns off L2 cache for the CPU1's portion of the
DRAM, and the OCM cacheing is turned off altogether. I guess I don't understand what you
are trying to debug here. The JTAG debugger is finnicky (but even that is better than the
gdb software debugger); when I was bringing up my system, I found that I had to HALT
CPU1 before I could set HW breakpoint that actually break--most of the time. Often, xsdk
on Ubuntu would just hang, and I have to restart it. As a last resort, I will move around an
infinite loop in an startup.S, or my C program, and try to bisect the problematic code. I
ASSUME you've seen my other blog entry on low level JTAG debugging:
http://henryomd.blogspot.com/2014/10/ways-to-study-linux-kernel-and-driver.html
Restrictlying debugger scope to only CPU1 may help, as well as deleting the symbol file
and attaching it to a HALTED CPU1. I don't know how else to help you other than sitting
down together over a GoToMeeting. But have hope; I found the low level difficult at first,
but after I settled on a repetitive process, it has been pretty stable for me.
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 22/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
I tend to think the MMU translation errors are not the cause of my problem anymore
because I studied XAPP1079 and XAPP1078 a lot more in-depth and found some
discrepancies in my boot.S. The boot.S in those app notes modified not only the MMU
settings, but also the very start of boot.S, adding some cpu0_catch/cpu1_catch
mechanism to determine where to jump to based on which CPU is running. I didn't have
that in my boot.S and that led me to find some issues related to that. I don't know how
this can happen because it is using a BSP for ps_1, but it looks like my cpu1app was
somehow compiled with XPAR_CPU_ID = 0, so when it runs the boot code, it will only let
CPU0 continue, but since it's running on CPU1, it gets branched to an endless WFE loop. I
think this may be the cause of the CPU1 suspension I'm seeing. I figured this out
debugging the XAPP1079 bare-metal/bare-metal configuration though and fixed it (by
getting rid of that CPU check code). I was so sure this would also fix my Linux/bare-metal
AMP problems, but CPU1 is still getting suspended once I do modprobe zynq_remoteproc
on the Linux/bare-metal AMP configuration. I ran out of time before the weekend to
verify the fixed boot code was used, but I'm pretty sure it was. I hope to figure this out or
find out more on Monday.
Do you know exactly how zynq_remoteproc gets CPU1 to start execution at the cpu1app
elf start address? When Linux releases CPU1, what does CPU1 then do? I imagine Linux has
to somehow tell it an address at which to start execution. I know on entire system reset,
CPU1 looks for non-zero address at 0xFFFF_FFF0 to jump to. I wonder if the same
happens if only CPU1 is reset and zynq_remoteproc just resets CPU1 and writes the
cpu1app elf address to 0xFFFF_FFF0, but then again, I don't think it can because that
whole process on entire system reset puts a bit of boot code in the upper reaches of OCM
for CPU1 to use (put there by the boot ROM), so there's no guarantee OCM is not in use by
the time Linux is up and running.
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 23/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
To answer your direct question, when you Google for the remoteproc, there isn't much
hit. I actually corresponded with another engineer (I think the link is in this blog
somewhere) who wrote YET another kernel module, to use this remoteproc module with
his TI DSP. I would be interested in finding out how many people out there actually use
this kernel module the way TI/ADI/Xilinx thought it would be used; I suspect not many.
Reply
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 24/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
Replies
Reply
Replies
Reply
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 25/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
I would like to use Ubuntu Linux on Core0 and Bare Metal on Core1. Do you have your project files
uploaded to github? I also would like to use vivado 2015.1 and build the SW without the SDK, just via
make (+ Makefile). Is that possible?
Reply
1. No github. I'd rather push my zynq_remoteproc mods to the ADI kernel branch, but they actually
want to mainline their work, so I don't know how things will shake out. I don't think I have enough
visibility with the ADI/Xilinx kernel developers (Lars, Michal, etc) to even send a pull request. In the
past, when they convinced themselves about the argument I made, they would just make the change
on their end. I don't see the benefit of making a github project for a blinking light bare metal code
running at DRAM 0x1fd00000 (510 MB)--started by the zynq_remoteproc. My "up" file addition is such
an easy change for anyone. I COULD put out my diff file, but then you would have to know how to
apply the patch to YOUR kernel, OR know how to use something like Buildroot/Yocto. In short, I
expect my project will be applicable to myself only, as everyone else will have his own setup, and
can read my blog entries to quickly figure out what he needs to do.
2. Vivado 2015.1: good luck; I am stuck on 2014.4 because my EE and SW colleagues are on 2014.4.
3. No SDK route: probably possible, but not interested in figuring it out right now. I want to know if
you get that working.
Reply
how much effort is it to adapt your vivado 2014 to 2015.1 changes...any experience? and later on
remove the sdk dependency?
Reply
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 26/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
Hi Henry,
I've adapted XAPP1078 and your instructions to Vivado 2015.1 and the Red Pitaya board:
https://github.com/pavel-demin/red-pitaya-notes/tree/master/projects/bare_metal_test
Cheers,
Pavel
Reply
Replies
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 27/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
you can give some inputs on how and where do I need to update the rpmsg modules to
remove the dependency on remoteproc. Is it in Zynq_remoteproc module where we setup
interrupts? Or can I remove the remoteproc completely from loading it.?
Best regards,
Diwakar Reddy
I haven't looked deeply into U-Boot, but figuring that out will be an entirely another
challenge for you. I suppose you are really sure about the requirement of the RTOS having
to control your car within a few ms, because if you could wait a few seconds, you could
potentially just use my solution. Consider that a full blown Chromebook cold boots in <
10. Waking back up from sleep is like a second or two. Would a customer really want to
drive a car within 2 second of pressing the power button?
Reply
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 28/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
Replies
But when I thought about it again, I wondered if Diwakar's system could tolerate not
hearing back from the ARM CPU for the at least few seconds it takes to boot Linux and
then start the CPU1 bare metal app through the zynq_remoteproc.
Reply
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 29/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
I have followed above instructions and I have the same environment (petalinux 2014.4 + zed-board).
I changed zynq_cpun_start(0x1fe00000,1). When I modprobe, zynq_remoteproc, I get message saying
CPU1 is now up. I don't know if to trust that, as I do not get LED blinked. I also added a bit of code
from xapp1078, to increment a variable in OCM, but it's not changing either. In short, I don't think
processor 2 is running.
Reply
Replies
Reply
Publish Preview
About Me
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 30/31
2/23/2018 Henry Choi: Zynq AMP: Linux on CPU0 and bare metal on CPU1
Henry Choi
Follow 63
► January (3)
► 2014 (16)
► 2011 (1)
http://henryomd.blogspot.com/2015/02/zynq-amp-linux-on-cpu0-and-bare-metal.html 31/31