Hi, I'd like to know if there's any examples or resources that explain how to deal with SEMA4 on Linux userspace. I want to access to the SEMA4 registers dynamically in the application. I'm using iMX8M Mini with imx-5.10.72 kernel. I tried accessing SEMA4 registers using a mmap'ed pointer, but only could read, writing to register simply froze it without errors. I'd appreciate it for any tips.
#It seems iMX6SX has its SEMA4 Linux driver. Would it be okay to reuse it for the Mini?
Thanks in advance.
Solved! Go to Solution.
Reply to myself. I should have accessed to SEMA4 registers using a byte pointer..! It turns out that I missed it on the reference manual. Everything works fine now. Also, I could integrate the SEMA4 driver to iMX8MM successfully.
I'd like to revive this thread to ask how the SEMA4 driver can actually be used from Linux user space. Based on the hints provided by @BitBakery I was able to build a Yocto mickledore image for the IMX8MN-EVK board where the SEMA4 driver is enabled in the kernel.
Are there any examples how to use the SEMA4 driver from Linux userspace?
Hi, as far as you use SEMA4 on Linux userspace, you don't even need to enable the kernel driver. You can just access to SEMA4 registers directly via mmap'ing.
How to access SEMA4 registers
1. Find out the SEMA4 register addresses (base, gates, INE, NTF, etc). They should be on the reference manual. For example, SEMA4 base address for the iMX8MP is 0x30AC0000.
2. MMAP the base address so that you can access it from the userspace. You can access related registers by adding proper offsets to the base address. One thing to be aware of is that each register needs to be accessed by a specific type of pointer. (u8, u16, 32, etc). It's written in the reference manual.
* You can't lock/unlock CP1 gates from CP0, vice versa. iMX8 looks where register access coming from and protect any improper write access.
Ok, here's a rough sample code how to access the register. Hope this helps to give you an idea.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>
#include <fcntl.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#define PAGESIZE (4096)
#define SEMA4_BASE (0x30AC0000u)
#define SEMA4_UNLOCK (0x0)
#define SEMA4_CP0_LOCK (0x1)
#define SEMA4_CP1_LOCK (0x2)
int main(void)
{
void* pSEMA4 = NULL;
volatile __u8 *mmPtr = NULL;
int fd = open("/dev/mem", O_RDWR);
pSEMA4 = mmap(NULL, PAGESIZE, PROT_READ|PROT_WRITE,
MAP_SHARED, fd, SEMA4_BASE);
close(fd);
assert(pSEMA4 != MAP_FAILED);
// Locking SEMA4 Gate0 (CP0)
// CP0 refers the application core, in my case it's A53.
mmPtr = (__u8 *)(pSEMA4 + 0x0); // Gate0 offset is 0x0
*mmPtr = SEMA4_CP0_LOCK;
if (*mmPtr == SEMA4_CP0_LOCK) {
printf("SEMA4 lock success\n");
} else {
printf("SEMA4 lock failed : Currently locked by the other core\n");
}
// Unlocking
*mmPtr = SEMA4_UNLOCK;
if (*mmPtr == SEMA4_UNLOCK) {
printf("SEMA4 unlock success\n");
} else {
printf("SEMA4 unlock failed : Currently locked by the other core\n");
}
}
Thanks for the example, @BitBakery. This is similar to what I implemented in the meantime.
From the existing thread I had the impression that you had implemented a solution based on the driver, and I was interested how that would work. But after re-reading your messages I see now that I misunderstood that, and your example confirms my existing implementation.
That’s nice! Yeah, I messed around with the driver but ended up realizing didn’t need to deal with it.
you can check AIPS3 memory check to find the SEMA4, they should access by user space if they are R/W, if the register is readable only, maybe you couldn't write this, and you can refer to the imx6sx as example
Thanks for your reply. The reference manual says the SEMA4 gates are R/W registers, I don't know why I can't write on them from Linux.. By the way, SEMA4 node is missing under the AIPS3 in the imx8mm device tree. Is there a specific reason for that? Would it be okay to add it manually, based on the imx6sx devicetree?
Reply to myself. I should have accessed to SEMA4 registers using a byte pointer..! It turns out that I missed it on the reference manual. Everything works fine now. Also, I could integrate the SEMA4 driver to iMX8MM successfully.
you integrate the SEMA4 according to the imx6 successfully, right?
Yes, that's correct. I added the SEMA4 node to imx8mm device tree with its corresponding register address, then added the driver(source, Kconfig & Makefile). v5.10.72 kernel probed it alright according to dmesg. Thanks.
thanks for sharing, imx8mm doesn't have much information about this like imx6, but I think they should be similar, good to know that it works
Sure thing! As far as I see the reference manuals of the imx6 and 8, SEMA4 looked identical(structure, offsets, etc)