Why does ioremap fail?

I am trying to access the McASP control registers. Reading from the first one fails with the kernel oops stating “external abort on non-linefetch (0x1028)”. I dont know what that means. A minimum failing example of the code is below:

`
#include <linux/module.h>
#include <linux/printk.h>
#include <asm/io.h>

#define MCASP_START 0x48038000
#define MCASP_LENGTH 0x2000
#define PFUNC_REG_OFFSET 0x10

static int start(void)
{
pr_info(“Calling for ioremap\n”);
void *mcasp = ioremap(MCASP_START, MCASP_LENGTH);
if(mcasp == NULL) {
pr_info(“ioremap failed!\n”);
return -1;
}

u32 pfunc_reg = ioread32(mcasp + PFUNC_REG_OFFSET); // Kernel Oops here!
pr_info(“Success! PFUNC=%08X\n”, test);
iounmap(mcasp);
return 0;
}
module_init(start);
`

I have also tried request_mem_region around it, but that changes nothing. The sound drivers are not loaded, and the devicetree entry for the McASP is disabled, so there shouldn’t be any problems with conflicts.

Any help is greatly appreciated.
Marc

I believe ioremap works on virtual memory and not on physical memory so you have to take into account the MMU translation. Look in

arch/arm/mach-omap2/iomap.h

#define MA33XX_L4_WK_IO_OFFSET 0Xb5000000

This will translate your McASP address to 0xfa038000. Try that and see if that works.

Regards,
John

I am trying to access the McASP control registers. Reading from the first
one fails with the kernel oops stating "external abort on non-linefetch
(0x1028)". I dont know what that means. A minimum failing example of the
code is below:

<snip>

I have also tried request_mem_region around it, but that changes nothing.
The sound drivers are not loaded, and the devicetree entry for the McASP is
disabled, so there shouldn't be any problems with conflicts.

One way to get this error is if the hardware you are talking to is
disabled. You need to either enable the hardware via the device tree,
or otherwise manage to setup the low-level SoC registers so the McASP
is provided a clock, power, and is taken out of reset.

Most of the hardware blocks on the AM335x series can be individually
enabled or shut-down to save power.

I am trying to access the McASP control registers. Reading from the first
one fails with the kernel oops stating "external abort on non-linefetch
(0x1028)". I dont know what that means. A minimum failing example of the
code is below:

<snip>

I have also tried request_mem_region around it, but that changes nothing.
The sound drivers are not loaded, and the devicetree entry for the McASP is
disabled, so there shouldn't be any problems with conflicts.

One way to get this error is if the hardware you are talking to is
disabled. You need to either enable the hardware via the device tree,
or otherwise manage to setup the low-level SoC registers so the McASP
is provided a clock, power, and is taken out of reset.

Most of the hardware blocks on the AM335x series can be individually
enabled or shut-down to save power.

That is a good point. To understand how to enable the power and clock for McASP, look at the Starterware examples for McASP as they do everything you need to make this work.

Regards,
John

That is a good point. To understand how to enable the power and clock for McASP, look at the Starterware examples for McASP as they do everything you need to make this work.

Probably easier, and more productive to read the TRM for the AM335x processors . . . All address offsets should be listed there as well, and the introduction for hardware module will give a short explanation of what needs doing, in order to bring the module up.

That is a good point. To understand how to enable the power and clock for McASP, look at the Starterware examples for McASP as they do everything you need to make this work.

Probably easier, and more productive to read the TRM for the AM335x processors . . . All address offsets should be listed there as well, and the introduction for hardware module will give a short explanation of what needs doing, in order to bring the module up.

Yeah, thinking about what Charles said, if he defines the McASP in the device tree, it should setup everything he needs. One problem I’m not sure how to overcome, he needs a device driver defined for the McASP or else the clock and power won’t be setup. But if he has a device driver setup, then it will conflict with his application. So that is why I think he has to do all this manually.

Regards,
John

I’ve no idea how ioremap() works, never used it. But if it’s similar to how mmap() works on /dev/mem/, it does not matter what state the hardware module is in. Of course there are a few specified steps one must do in order to get a device working if it’s not already. But if the device is already on, and functional, you can essentially override that module with mmap() and /dev/mem/. But it’s probably not good idea, as the kernel will still think it has control . . .

Anyway, I’m not sure I’d exactly call this a “driver” per se, as it’s being done in userspace. But others might argue it’s what’s called a userspace driver . . . and yeah, I do not know about that. If you start changing pixels on your screen by poking at memory locations through /dev/mem/ does that mean you’ve created a graphics driver ? No . . .

I’m not familiar with the McSPI hardware module, but this seems to explain a good bit. And seems analogous( similar ) to how one would enable the ADC module - Which is the only module I have hands on experience with by poking it’s registers . . e.g. turning the clock on, etc.

https://github.com/BeaglePilot/PRUSS-C/blob/master/PRUSS_LIB/AM335X_StarterWare_02_00_01_01/drivers/mcspi.c#L378-L469

errr ooops. highlighted too many lines. https://github.com/BeaglePilot/PRUSS-C/blob/master/PRUSS_LIB/AM335X_StarterWare_02_00_01_01/drivers/mcspi.c#L422-L469

I’ve no idea how ioremap() works, never used it. But if it’s similar to how mmap() works on /dev/mem/, it does not matter what state the hardware module is in. Of course there are a few specified steps one must do in order to get a device working if it’s not already. But if the device is already on, and functional, you can essentially override that module with mmap() and /dev/mem/. But it’s probably not good idea, as the kernel will still think it has control . . .

Anyway, I’m not sure I’d exactly call this a “driver” per se, as it’s being done in userspace. But others might argue it’s what’s called a userspace driver . . . and yeah, I do not know about that. If you start changing pixels on your screen by poking at memory locations through /dev/mem/ does that mean you’ve created a graphics driver ? No . . .

I was talking about the McASP device driver that is defined in the devicetree as that is the only way to setup the pinctrl, power and clocks for the McASP.

Regards,
John

errr ooops. highlighted too many lines. https://github.com/BeaglePilot/PRUSS-C/blob/master/PRUSS_LIB/AM335X_StarterWare_02_00_01_01/drivers/mcspi.c#L422-L469

I think he was using McASP, not McSPI :wink:

Heh ooops. Oh well McASP, McSPI, it’s all the same right ? :wink: hah

Anyway, theres an mcasp.c file in that same git directory. Looks more complicated.

Thanks for the help everyone, I think I know where to go from here now.
John, I am fairly certain ioremap works with physical addresses. Its declaration is ioremap(phys_addr_t phys_addr, size_t size). I did try 0xFD038000 anyway and it gave the wrong result for the revision number of the McASP.

Charles, after some additional googling, I think you are correct. Because I have the McASP disabled in the device tree, it is turned off and cannot be accessed. I’m not exactly sure how to turn the McASP/clocks on, but will start looking in the TRM.

to turn it on just do:

https://github.com/RobertCNelson/dtb-rebuilder/blob/4.1-ti/src/arm/am33xx-overlay-edma-fix.dtsi#L31-L33

in your custom *.dts

Regards,

Wont this also cause it to load the sound driver and possibly interfere with its operation? I need exclusive access to the device.

As long as you don't have the "sound" details in the device tree node..

Regards,

It should be possible to enable the device without using device tree though, if that’s your wish. I’ve not done this personally with McASP, but I have manually turned on, and used the on die ADC module in such a manner.

Using device tree sure is easier, but in any case you really need to know the hardware well in order to enable a hardware module exactly how you want it enabled. Which is why I suggested( before ) reading the TRM section for the hardware module you need / want to understand.

Changing my device tree overlay to include status=“okay” does not seem to be enough to enable me to access that address, whether or not the sound stuff is still around. Note that I am only messing with an overlay. Do I need to change the device tree the board is booted with?

Looking into the source for the davinci-mcasp audio driver that gets loaded by default, there are calls to pm_runtime_get_sync(mcasp->dev) and pm_runtime_put(mcasp->dev), which are probably needed in my code. Next step is to figure out how I am going to get a struct device for the McASP.

Changing my device tree overlay to include status="okay" does not seem to be
enough to enable me to access that address, whether or not the sound stuff
is still around. Note that I am only messing with an overlay. Do I need to
change the device tree the board is booted with?

Yeap... It's gotta be in the dtb you boot with..

Looking into the source for the davinci-mcasp audio driver that gets loaded
by default, there are calls to pm_runtime_get_sync(mcasp->dev) and
pm_runtime_put(mcasp->dev), which are probably needed in my code. Next step
is to figure out how I am going to get a struct device for the McASP.

Regards,

OK, so lets see if we can get a better understanding of what you need to do because this has been confusing to me also. Read Documentation/bus-virt-phys-mapping.txt and you will see they reference ioremap under PCI Memory access; however, accessing physical memory/registers, they talk about using phys-to-virt(phys_addr).

Also, in arch/arm/include/asm/io.h, line 328

/*

  • ioremap and friends