Using EMC_MRW command to write mode register

Hello,

I am revising the linux kernel based on Nexus 9, of which the chipset is 64-bit Tegra K1.

I am trying to use EMC_MRW to write the mode register MR16.

The format of EMC_MRW is shown as following.

Bit /Description
31:30 /Chip selection, 0x2 for dev0, 0x1 for dev1
27 /USE_MRW_EXT_CNT (0=select between SHORT/LONG; 1=select between EXT1/EXT2)
26 /USE_MRW_LONG_CNT (0=short,1=long)
23:16 /Register address (0x10 for MR16)
7:0 /Data to be written

Based on the above format, I tried to write MR16 with 0x401000ff, which means write to the dev0, with address of MR16, and the writing data is 0xff. However, the value of register does not change. Before I wrote, the value is 0x1b, and the value remains 0x1b after the writing.

Do you have any idea what might be the reason, please? Is it possible that the register MR16 is not activated in the chipset?

Thanks a lot!

“I tried to write MR16 with 0x401000ff,”
How did you try to do this? (in a program you wrote, just tried to write to memory location with some utility)

Are you aware that in ‘user space’ all the memory is virtualised?
In user space, access to peripheral registers is locked down - so you cannot do it.

You must be in ‘Kernel space’ to be able to access any of the peripheral registers.

I do not know what you are trying to do in the EMC_MRW register
but messing around with a peripheral should generally be done in the Kernel drivers.

““I tried to write MR16 with 0x401000ff,”
How did you try to do this? (in a program you wrote, just tried to write to memory location with some utility)”

I wrote a module which initializes the function to use EMC_MRW command to write the specified mode register MR16. Linux kernel provides some assembly sentences to write the hardware with specified address and value. The EMC_MRW command will be translated to the assembly sentences and thus we can write the mode register MR16.

About the “User/kernel space”, I wonder how can I know whether I am in the user or kernel space.

Thanks very much!

“I wrote a module which initializes the function to use EMC_MRW command to write the specified mode register MR16.”
Sounds like you have tried to built it into kernel space.

You need to make sure the module you wrote is either loaded during boot or is in the boot image.

“Linux kernel provides some assembly sentences to write the hardware with specified address and value.”
Assembly code should not be necessary. Have a look around for Nvidia defines for other registers in the memory controller, there should be some pointer defines which allow mapped (struct) access to the registers.
Additionally, assembly code does not guarantee register access.

"About the “User/kernel space”, I wonder how can I know whether I am in the user or kernel space. "
Add a printk to the module, check the boot log (dmesg) for your printk.
(printf should not/cannot be used in kernel space,
printk should not be available in user space - I think)

Thanks a lot for your reply!

“You need to make sure the module you wrote is either loaded during boot or is in the boot image.”
The module is in the boot image. And I just flashed the boot.img to Nexus 9 and run.

“Add a printk to the module, check the boot log (dmesg) for your printk.
(printf should not/cannot be used in kernel space,
printk should not be available in user space - I think)”
I added the printk in the code, and found that it can print the messages I want. So it means that I am in the kernel space, right?

Because I can read out the value of register, I think I do have the access privilege to the register. It looks like that I just cannot write it, or maybe the write operation is not correct.

BTW, the value read out from the register is not matched with the system status. The value I read out is 0x1b, meaning that several memory banks are not refreshed, which is not possible. Because no one can stop the refreshing of the memory banks. So I wonder if it is possible that the register MR16 is not activated in the chipset.

“I added the printk in the code, and found that it can print the messages I want. So it means that I am in the kernel space, right?”
Yes, sounds like it to me.

"It looks like that I just cannot write it, or maybe the write operation is not correct.

BTW, the value read out from the register is not matched with the system status. The value I read out is 0x1b, meaning that several memory banks are not refreshed, which is not possible."
I think your assertion is correct - the access to the register is not correct hence reading back values that cannot be right.

Have a look around for Nvidia defines for other registers in the memory controller, there should be some pointer defines which allow mapped (struct) access to the registers.
Use these same structs.
Find some code that uses these structs, they will probably have a (base) pointer to the registers you need. Use this base pointer.

Try adding your code into where you find the registers being used instead of writing your own function.

“I am revising the linux kernel based on Nexus 9, of which the chipset is 64-bit Tegra K1.”
Documentation for this is not easily available so it is tricky to work things out.

“Have a look around for Nvidia defines for other registers in the memory controller, there should be some pointer defines which allow mapped (struct) access to the registers.
Use these same structs.”

OK, I will try this

“Find some code that uses these structs, they will probably have a (base) pointer to the registers you need. Use this base pointer.”

I initialized the base address(pointer) to the register MR16 according to the Tegra K1 technical manual.

“Try adding your code into where you find the registers being used instead of writing your own function.”
I see, will try in this way. Thanks!

“Documentation for this is not easily available so it is tricky to work things out.”
Yes. it is not easy to get. I applied the access to download the Tegra K1 technical manual from Nvidia website.

Hi GE_Chen,

“Have a look around for Nvidia defines for other registers in the memory controller, there should be some pointer defines which allow mapped (struct) access to the registers.
Use these same structs.”
I tried other register MR1 which is accessed by the memory controller through the same command EMC_MRW. The format to write MR1 is just the same as I wrote to MR16 (using assembly codes). However, before writing to MR1, the value of this register is 0x1b (just the same as MR16), and after writing, the value remains 0x1b. There must be something wrong. But I am quite sure that the read/write command format is correct.

“Try adding your code into where you find the registers being used instead of writing your own function.”
I also tried this one. Implemented the codes in where the EMC_MRW caommand and the corresponding EMC functions are defined. But nothing changed.

I wonder if there is any other way to make sure that the register value is changed after write, instead of using the read-write-read method, cause I am not quite sure that the read operation brings no influence to the register.

Thanks in advance!

Hi

“before writing to MR1, the value of this register is 0x1b (just the same as MR16), and after writing, the value remains 0x1b. There must be something wrong.”
Not necessarily. Some register are write only, that is you can write to them but reading them will return unspecified results.

Check the reference manual for the register in particular…

“based on Nexus 9, of which the chipset is 64-bit Tegra K1”
As far as I know - Nvidia have not released the TRM for the 64bit version of the Tegra K1.

“I wonder if there is any other way to make sure that the register value is changed after write”
What is the write suppose to do?
See if the change to the register causes the correct change in behaviour - if that is possible.
OR
Write a totally invalid value - the system should just fail/lock up/not boot…

Hi,

Thanks very much for your reply.

“Check the reference manual for the register in particular…”
I checked and found, yes, both registers (MR16 and MR1 who read out value being 0x1b1b) are Write-Only register. That explains why the read-out value does not make sense!

“As far as I know - Nvidia have not released the TRM for the 64bit version of the Tegra K1”
Yes, not specifically for 64-bit. But the TRM I referred seems to include the information of both 32-bit and 64-bit.

“See if the change to the register causes the correct change in behaviour - if that is possible.
OR
Write a totally invalid value - the system should just fail/lock up/not boot.”
I tried both of the methods, but the results show that the register is not changed after writing. For example. I write “0xff” to MR16 which means that the whole memory stopping refresh, which will definitely lead to a system crash, but there is not…

"For example. I write “0xff” to MR16 which means that the whole memory stopping refresh, which will definitely lead to a system crash, but there is not… "
Sounds like you may need to get out an oscilloscope or logic analyser in order to check whether it changed anything or not.

It has been years since I had to check DRAM refresh but I think there may be a refresh line and then the address lines (CAS and RAS) get cycled.
I have not looked at the signals for DDR so I do not know if this is still the case.

Sorry but when you get to this level of ‘firmware’ - you are just going to have to measure it. It may not be possible to see what is going on just in software! If you are unwilling to open up the Nexus9 I do not think there is any more that you can do.

Well, I see.
Thanks very much for your suggestions.

I understand this situation. But it might be difficult for me to use an oscilloscope to test the register on Nexus 9…

Anyway, I will keep trying other writing formats and keep you update in case I get some interesting results.
Thanks so much!