mmap and access to GPIO config registers in an ARM processor - arm

Im struggling to read(and write) to HW registers from Linux user space. The goal is to configure some GPIO pins from and be able to set and read this pins.
According to the spec for the processor(imx27 from Freescale) the physical address for the register bank controlling GPIO this is 0x10015000
My assumption was that I could use something like this:
unsigned long *gpio;
fd = open("/dev/mem", O_RDWR);
gpio = (unsigned long *) mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x10015000);
I now expected to be able to read and set data to the registers in the processor. The problem is that it does not matter which location I read, I always get 0.
For example register in physical location 0x10015220 contains a register showing which pins are in us as GPIO. This Defaults to 0xFFFFFFFF. Reading this register I expected to get something different than 0:
printf("PTC_GIUS: 0x%08lX\n", gpio[0x220]);
gives PTC_GIUS: 0x00000000.
Where am I going wrong ?

The mmap on /dev/mem should work. Have you tried running your code as root? Maybe some security is preventing your program from accessing the address-space. Also make sure you've passed the correct physical address of your GPIO-Space.
The approach you've used works on my Cortex-A8 ARM-board running linux without problems.
If you can't get it working there is not much you can do except finding or writing a device-driver for the gpio (writing one is not that hard btw.).
With a bit of luck someone already did that for you. Does a node named /dev/gpio exist in your filesystem? If so you already have a driver.
A google search on /dev/gpio will give you all details on how to use it. You may also find the source for a simple gpio driver that you can modify to suit your needs.

Also, if you're using a kernel source code from 2009 and on, you should open /dev/mem with the O_SYNC flag set, if you want your memory access to be uncached.

If you are using a recent version of the Linux kernel it may be blocking access to the /dev/mem device. User mode access to that device is deprecated and dangerous. It is used mainly for user mode access to video memory within X. In embedded projects it can be useful to have access to memory mapped hardware (like GPIO).
Check your Kernel compile flags for CONFIG_STRICT_DEVMEM or other flags that restrict access to /dev/mem. It could be mistakenly blocking access to this memory range.
However, as Nils mentioned the best solution is to find a gpio module for the iMX27 or write your own.

Related

Cortex-M33 MTB configuration - When MTB buffer is full

I am exploring the MTB feature on Cortex-M hardware and doing experiments on Arm mps2+ FPGA board with the Cortex-m33 image, which enables the TrustZone technique. From what I learned, the MTB can be configured to record non-sequential branches of the execution. The record will be written directly to the allocated SRAM by the MTB unit automatically. During the experiment, I have several questions.
When the MTB buffer is full, there are two ways to handle it. One way is to rewrite the buffer from the very beginning. Another way is to set a watermark, which will let the PE enter the Debug State. I checked the document that the Debug State means we need an external debugger or another core to handle. Since the board I use is single-core and I prefer not to use the external debugger, is there another way to notify the CPU without halting it when the MTB buffer is full?
Based on the first question, I had several trials:
I configured the DWT comparator to monitor the data address write,
but it seems DWT cannot monitor hardware writing like MTB does.
I configured Non-secure MPU to set the MTB buffer region as RO, but it still cannot trigger a secure fault. I checked the document ARM CoreSight MTB-M33 page A2-26: The MTB-M33 ensures that trace write accesses have priority over AHB accesses. Is that the reason why the
MPU can not constrain MTB writing?
I also configured SAU to set the MTB buffer as secure, it still cannot trigger the secure fault when non-secure trace writing happens.
Then I went back to read the MTB document. MTB actually has the MTB_SECURE register that can partition the MTB buffer as secure or non-secure. But I don't know is that because the board or the image I use does not fully implement the MTB, I cannot modify the MTB_SECURE register except for the last two bits.
So at last, is there another way to notify the CPU without halting it when the MTB buffer is full? Like what Intel Processor Trace does, which will generate an interrupt.
I hope I describe the question clearly and I very appreciate if someone could give me any suggestion. Thank you so much!

Handling PCI read/write to configuration space in a QEMU device

I'm working on implementing a simple PCI device in QEMU and a kernel driver for it, and I have some trouble with handling pci_read/write_config_* function calls from the device side.
Unlike simple rw operations on a memory mapped bar, where the MemoryRegionOps callbacks receive the exact offset used by the driver, the config_read/write callbacks implemented as members in PCIDevice struct, receive an address that went through some manipulations/mapping that I have a hard time understanding.
Following the code path up to pci_config_host_read/write in QEMU sources, and the same in the kernel side for pci_read/write_config_* functions, didn't provide any clear answers.
Can anyone help me understand how to extract the config offset used by the driver when calling the pci config rw functions?
If you set your PCI device model up to implement the QEMU PCIDevice config_read and config_write methods, the addresses passed to them should be the offsets into the PCI config space (ie starting with the standard 0 == PCI_VENDOR_ID, 2 == PCI_DEVICE_ID, 4 == PCI_COMMAND and so on, and any device-specific stuff after the 64 bytes of standardized config space).

Programming GPIO pins on a FINTEK F81866A chipset

I have a Cincoze DE-1000 industrial PC, that features a Fintek F81866A chipset. I have to manage the DIO pins to read the input from a phisical button and to set on/off a LED. I have experience in C++ programming, but not at low/hardware level.
On the documentation accompanying the PC, there is the following C code:
#define AddrPort 0x4E
#define DataPort 0x4F
//<Enter the Extended Function Mode>
WriteByte(AddrPort, 0x87)
WriteByte(AddrPort, 0x87) //Must write twice to entering Extended mode
//<Select Logic Device>
WriteByte(AddrPort, 0x07)
WriteByte(DataPort, 0x06)
//Select logic device 06h
//<Input Mode Selection> //Set GP74 to GP77 input mode
WriteByte(AddrPort, 0x80) //Select configuration register 80h
WriteByte(DataPort, 0x0X)
//Set (bit 4~7) = 0 to select GP 74~77 as Input mode.
//<input Value>
WriteByte(AddrPort, 0x82) // Select configuration register 82h
ReadByte(DataPort, Value) // Read bit 4~7(0xFx)= GP74 ~77 as High.
//<Leave the Extended Function Mode>
WriteByte(AddrPort, 0xAA)
As far as I understood, the above code should read the value of the four input PINs (so it should read 1 for each PIN), but I am really struggling to understand how it actually works. I have understood the logic (selecting an address and reading/writing an hex value to it), but I cannot figure out what kind of C instructions WriteByte() and ReadByte() are. Also, I do not understand where Value in the line ReadByte(DataPort, Value) comes from. It should read the 4 PINs all together, so it should be some kind of "byte" type and it should contain 1 in its bits 4-7, but again I cannot really grasp the meaning of that line.
I have found an answer for a similar chip, but it did not help me in understanding.
Please advice me or point me to some relevant documentation.
That chip looks like a fairly typical Super I/O controller, which is basically the hub where all of the "slow" peripherals are combined into a single chipset.
Coreboot has a wiki page that talks about how to access the super I/O.
On the PC architecture, Port I/O is accomplished using special CPU instructions, namely in and out. These are privileged instructions, which can only be used from a kernel-mode driver (Ring 0), or a userspace process which has been given I/O privileges.
Luckily, this is easy in Linux. Check out the man page for outb and friends.
You use ioperm(2) or alternatively iopl(2) to tell the kernel to allow the user space application to access the I/O ports in question. Failure to do this will cause the application to receive a segmentation fault.
So we could adapt your function into a Linux environment like this:
/* Untested: Use at your own risk! */
#include <sys/io.h>
#include <stdio.h>
#define ReadByte(port) inb(port)
#define WriteByte(port, val) outb(val, port)
int main(void)
{
if (iopl(3) < 0) {
fprintf(stderr, "Failed to get I/O privileges (are you root?)\n");
return 2;
}
/* Your code using ReadByte / WriteByte here */
}
Warning
You should be very careful when using this method to talk directly to the Super IO, because your operating system almost certainly has device drivers that are also talking to the chip.
The right way to accomplish this is to write a device driver that properly coordinates with other kernel code to avoid concurrent access to the device.
The Linux kernel provides GPIO access to at least some Super I/O devices; it should be straightforward to port one of these to your platform. See this pull request for the IT87xx chipset.
WriteByte() and ReadByte() are not part of the C language. By the looks of things, they are functions intended to be placeholders for some form of system call for the OS kernel port IO (not macros doing memory mapped IO directly as per a previous version of this answer).
The prototypes for the functions would be something along the lines of:
#include <stdint.h>
void WriteByte(unsigned port, uint8_t value);
void ReadByte(unsigned port, uint8_t *value);
Thus the Value variable would be a pointer to an 8 bit unsigned integer (unsigned char could also be used), something like:
uint8_t realValue;
uint8_t *Value = &realValue;
Of course it would make much more sense to have Value just be a uint8_t and have ReadByte(DataPort, &Value). But then the example code also doesn't have any semicolons, so was probably never anything that actually ran. Either way, this is how Value would contain the data you are looking for.
I also found some more documentation of the registers here - https://www.electronicsdatasheets.com/download/534cf560e34e2406135f469d.pdf?format=pdf
Hope this helps.

Pci express - communicate kernel -> graphic card

The final goal is to be able to write to a PCIE device from the kernel, without the already made functions, to understand the inner working (and then, obviously, use them again).
I saw the PCIE specs which are 800+ pages (the 3.0 especially).
Huge is not enough to describe that.
I cannot afford to go along those at the step I currently am (reading 2.0 and 3.1 would be very time consuming).
I read many sources and it seems that we can write to pcie via messages (and not buses anymore like in pci).
Pcie should be memory mapped so I think that we could write to that memory from the kernel and aknowledge the driver that we did it.
The driver will then make the out(l/b) assembly instruction to notify the device in question.
This my very high level understanding of pcie (I don't want to dive into the spec details now). It may not be correct though.
If someone could tell me where I am wrong in my thinking, that would be very helpful.
Here is the pseudo code of my thinking (no error checking and such):
static int64_t my_driver_address;
pcie_write_device(uint32_t * my_data_physical_address) {
// we pass the physical address where the data is. It has to be contiguous.
pcie_send_address(&my_driver_address, my_data_physical_address);
// now the device is acknowledged that some data has been mmaped, knows where and will treat it as such
}
pcie_read_device(anytype_t ** buff){
// this function calls the inq assembly instruction and store the resulting address in the pointer
ptr * address_to_read = pcie_get_data();
// read the mmaped memory region. No mem allocation code.
*buf = get_data_from region(address_to_read);
// now data from device is in the buff, ready to be sent to the OS or anything..
}

Write value to parallel port register

I'm trying to write to my lpt register with the function outb(0x378,val);
well.. I tried to debug with the call int ret=inb(0x378); I always get the ret=255 no matter what value I insert with outb before.
*I'm writing on the kernel mode since my program is a driver, therefore I didn't use ioperm() etc.
thank you in advance.
You have the parameters of outb function wrong, correct order is :
outb(value, port)
so you have to change your code to do:
outb(val, 0x378)
For more details please read Linux I/O Programming Howto .
Do you know for a fact that you have a parallel port installed at that address?
Get yourself a small low-current LED. Stick the long end in one of pin 2 (LSB) to pin 9 (MSB) and the short end in pin 25 (ground).
Try writing various values and see if you can get the LED to change by the bit value of what you write.
This should work (unless as previously mentioned you've gotten it programmed in an input mode) Being able to read back the port value is less certain, depending on the type of parallel port and implementation details (for example, you probably couldn't with the buffer chip that implemented it in the original PC)
Also note that most USB "printer" adapters don't give you bitwise register access. Something hanging off of the PCI or PCMCIA, etc may also have problems with direct register access at the legacy port address. There are nice USB parallel interface chips such as the FT245 and successors which you can use if you don't have a "true" parallel port hanging off the chipset available.
Have you set the direction register? If it is set as input then you will read what is on the port.
inb(0x378) is not required to return what was written; at least I've seen chips to behave so. Well, since you, at some point, have called outb, you know what's on anyway.

Resources