Question

I'm a newbie to writing device drivers.

I want to write a device driver for a peripheral on an ARM platform.

1st question: Is it different to write a device driver for a peripheral on ARM platform than on x86 in Linux?

2nd question: I checked /proc/iomem file to view current address map of the processor. However, not all peripherals including the one to which I want to access do not exist in that file. How can I include the address range of a peripheral?

3rd question: What is the importance of a device tree in writing a device driver?

Was it helpful?

Solution 2

1. As long as the peripheral is interfaced similarly to the SoC(i.e. uses the same hardware interface on both the platforms), the same driver can be used on both x86 and ARM. This is the advantage of developing modular drivers independent from the Linux kernel core.


2. If your particular peripheral does NOT exist in the current address map(/proc/iomem) then it could mean one of two possibilities :

  • The device driver is not loaded yet.
  • The device uses other form of addressing (NOT memory mapped I/O)

Any additional info about the peripheral? How is it connected to the SoC?


3. A device-tree in the Linux kernel is used to describe the numerous hardware (both-on-chip and peripherals), their inter-connectivity and the basic params applicable for their proper configuration and initialisation on a specific platform/board for which the device-tree is written.

Essentially it performs the same functions and the "board-file" found in current Linux kernel. It also reduces the dependency of bootargs for initial configuration as the same can be provided in the device-tree. More info on device trees.

OTHER TIPS

If the driver does not exist in the kernel source tree, and the device is memory mapped in the device address space, then the device resources (adress region, irq lines) has to be declared somewhere. In older version of the kernel, this was the responsibility of the board file, but now it has moved to the device tree.

So the main difference with x86 architecture is not how you write a driver, but rather how you match devices and driver. On x86, you have for instance pci driver, and pci devices that are discoverable. On ARM, there is generally no such self describing hardware, and to emulate the whole device / driver dance, the platform bus was created.

So a typical device driver on ARM is a platform driver, and the associated devices are platform devices. An example ethernet mac driver from the current kernel is here.

In the above linked driver, the driver code doesn't know where the device lives. This info is passed to the driver at probe time, using the platform_device object. And the platform device can be described like this (source):

static struct platform_device at91sam9260_eth_device = {
        .name           = "macb",
        .id             = -1,
        .dev            = {
                                .dma_mask               = &eth_dmamask,
                                .coherent_dma_mask      = DMA_BIT_MASK(32),
                                .platform_data          = &eth_data,
        },
        .resource       = eth_resources,
        .num_resources  = ARRAY_SIZE(eth_resources),
};

Platform device can be created from c code as shown here, or they can be described in device tree. In both cases, you won't see anything in proc/iomem until the device has been probed by the driver. This his in contrast with the x86 world where most devices are PCI devices.

Here is the same device, but described in a device tree file :

               macb0: ethernet@fffc4000 {
                        compatible = "cdns,at32ap7000-macb", "cdns,macb";
                        reg = <0xfffc4000 0x100>;
                        interrupts = <21 IRQ_TYPE_LEVEL_HIGH 3>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_macb_rmii>;
                        status = "disabled";
                };

To export information about address range of a device to /proc userspace interface you have to register this region in your driver to the kernel:

request_mem_region()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top