Linux device driver for banana pi and device tree - c

I'm trying to write ethernet driver for Linux kernel 4.13.x for Banana Pi M2 ultra.
Some time ago so called "device tree" (DT) has been introduced in Linux kernel infrastructure.
I have no much experience with using DT while writing device drivers and because of that
I've got a few questions.
As far as I know - in case of banana pi system - it is needed to provide some clock source for given
peripheral device. It is function of CCU in banana pi to provide such a clock. The CCU is memory mapped
resource available at some address in the linux kernel. I'd like to write driver for ethernet which
needs some clock from CCU.
I know that physical address of CCU must be mapped via ioremap() or similar function to virtual address.
My question is how can I fetch the virtual address of CCU in my ethernet driver? Is it possible to do via
device tree? If yes - how to do this? Or maybe this virtual address can be get another way?
I'm just not sure if it is done (fetching virt address) via DT or just by some procedure or via global pointer.
Any ideas or suggestions?

There are examples in Linux kernel for platform drivers. I have worked on i2c and i2s on raspberry pi so I can quote those examples.
In http://elixir.free-electrons.com/linux/v4.3.2/source/drivers/i2c/busses/i2c-bcm2835.c
Look at the probe function, it calls the subsystem api
platform_get_resource(pdev, IORESOURCE_MEM, 0);
This can gives physical address which is ioremap ..
For this it is required to create a device node in device tree as in
https://github.com/raspberrypi/linux/blob/rpi-4.9.y/arch/arm/boot/dts/bcm283x.dtsi
check for i2c0 device node in file bcm283x.dtsi.
The reg key is where physical address is stored
reg = <0x7e205000 0x1000>;
physical add size
Hope this help you.
Device tree may be considered analogus to platform data previously

Related

PCIe multiple child-devices

I am writing a Linux kernel driver (kernel 4.9) for our custom setup.
We do use a ARM64 based board with a PCIe interface.
Connected to the interface we have an extension board with a FPGA on it.
At this moment I succeed at creating a device that registers my FPGA with some basic functions, like reading the version of the FPGA in a certain register in the FPGA.
In the FPGA we do have some additional "devices" like GPIO, memory regions ... that I would like to add as its own chardevice. We do have existing drivers for these.
Normally, Linux goes over the DTB and calls the correct driver for our FPGA, following the correct drivers for our child devices.
Now I would like to archieve the same with this PCIe interface. To do this, I look for a node in my DTB fpga and add its children.
for_each_available_child_of_node(np, nc) {
subdev = kzalloc(sizeof(*subdev), GFP_KERNEL);
list_add(&subdev->subdev_entry, &priv->subdev_list.subdev_entry);
...
}
list_for_each_entry(subdev, &priv->subdev_list.subdev_entry,
subdev_entry) {
ret = mfd_add_devices(priv->dev, PLATFORM_DEVID_NONE,
subdev->mfd_cell, 1, NULL, irq_base, NULL);
if (ret) {
dev_err(priv->dev, "Failed to add mfd cell\n");
goto err_mfd_add;
}
}
For some reason, the driver is not loaded for its children.
print's in the device drivers probe function shows nothing, not being called.
Added print's to the loops and it shows its children (all properties and values check out with what I set in the DTB).
Yes, the driver is compiled an available in the kernel.
I also tried building the driver as a kmod and load it that way, no change in behaviour. The output of lsmod shows the module is loaded but not used.
Somebody got an idea why my driver is not being loaded?
EDIT:
I also can see the "nodes" from my DTB that should be created as a chardevice.
They can be found in the expected location /sys/class/my_fpga/fpga/device/, in this case GPIO.
Under the GPIO folder I can see the driver_override (which is (null) ), modalias, power, sybsystem and uevent.
So my device (my_fpga) seems to be enumerated, only its children are not created.
A reboot does not solve it, nor a rescan of the PCIe-bus. The extension-board is powered via an external powersupply and is already configured before booting Linux

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).

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..
}

How's the Major number allocated for platform device driver?

I wonder how the major number is allocated for platform device driver.
For example, in the driver code, I don't see any of the function calls like
alloc_chrdev_region()
or
register_chrdev_region()
Somebody, please make me understand this.
Thank you.
Kernel creates a great deal of devices attached to various virtual buses (which may or may not represent a physical one). Only some of those devices can be meaningfully accessed directly from user space. And only a subset of those relies on "device node" interface to do so (as ample other options exist in modern kernels). If this particular interface is not used by a driver, then there's no need whatsoever to allocate device node numbers.
Inside the kernel devices are located by their affiliation to particular buses (using internal device names and bus ids). For example, mcspi driver registers as "device" on "platform bus" and as "bus master" on "spi bus". Upon seeing that bus master had registered, spi subsystem will trigger a "bus rescan" on a newly connected bus.
The spidev driver is rigged in such a way as to always "match" an imaginary device present on every spi bus, so it will get instantiated for every "bus master" registration. It will create the user space device node which can be used for direct communication with its "bus master" (spi bus controller, mcspi in this particular case).
Controller doesn't need to be exposed. Hence, no device nos.
On the other hand, SPI devices do require a MAJOR?MINOR no defined in spidev.c, here it is registering the device. And on the top of the same file, there's a macro for the major no defined as:
56 #define SPIDEV_MAJOR 153 /* assigned */
57 #define N_SPI_MINORS 32 /* ... up to 256 */

how to use ioremap() api from user space to read and write registers on SPI Flash memory in uClinux

I am writing one sample application which is used to read registers and write particular value on given SPI Device address.
I am using altera spi 1.0 driver and got base address as 0xE5002460 while registering spi device.
I want to read/write registers from SPI Flash from user space using ioremap call.
Is there any code snippet or any example about how to use ioremap function which can directly read value of registers from base address given without writing any specific driver for that?
#Ritesh, ioremap api is used in the kernel space to memory map the device/module for ex:SPI registers which returns virtual address. This address can be used only by ioread[8|16|32] and iowrite[8|16|32] api's to read or write to the spi registers. You can use mmap to map the SPI registers. Go through the link mmap slower than ioremap.

Resources