Skip to content

Platform driver

Zubeen Tolani edited this page Aug 23, 2016 · 4 revisions

Why platform driver ?

It sounds so good that the code is generic and can be used on different platforms, but thats not completely true. Just think about it, how can a developer, who writes the core bus driver, can accommodate all the features and limitations of vast variety of hardwares that are present in the market ? Its practically impossible to do so. To tackle with this problem, the core bus drives has a lower layer of platform driver.

The platform driver is specific to the platform on which the rest of the software stack is to be deployed. It is closest to the hardware and needs to be developed by one who has good knowledge of how the concerned piece of hardware works. This driver accommodates all the features and limitations of the concerned hardware.

How does it fit in the software stack ?

While the core bus driver is designed, a well documented API interface for the platform-driver is also designed. The developer implementing the platform driver uses this documentation to implement all the APIs. Its the job of the developer to include as many features of the hardware, as gracefully as he can.

Okay, I got it. So how to implement a platform driver ?

NOTE : As the GSoC time period ends, not all the APIs of the parallel interface has been designed. Only a few of them, that are used for host and client driver registration, have been designed.

The parallel_interface is being developed as a bus. the Linux device model assumes that for all the bus, there is a host or bus-cotroller device for example the i2c host or the McSPI controller on the omap4 processors. The host device is considered as a platform device and is bound to a matching platform driver.

For the platform driver to work, the driver :

  1. Must include parallel_interface.h file.
  2. Must register itself as a platform driver, with matching struct of_device_id.
  3. Once probed, the driver should use pi_core_register_host() API to register the host device. Note that for now, the core bus driver only supports one pi bus host device. Registering more than one host device would produce undefined results.
  4. Once the host device is registered, the platform driver must use this host device to register all its child devices by using the pi_core_register_devices() API.
  5. Should also use the pi_core_unregister_host() API to unregister the the host device when the platform driver is removed or the host device is itself removed.

For now, thats all you need to do to get the registration part of the platform driver. For more information go onto the links for APIs and the data structures.

Relate it to the project now :

The platform driver in the software stack that this project is developing is the pi-bus driver. On looking the source, you will find that it in-fact does all the required things, mentioned in the previous section. The pi-bud drvier :

  1. Includes the parallel_interface.h file.

        #include "parallel_interface.h"
    
  2. Initializes and registers itself as a platform driver

       static int pi_bus_rpmsg_probe(struct rpmsg_channel *rpdev)
       {
            int ret;
            struct platform_driver *pibus_pdrv;
            log_debug();
              
            pibus_pdrv = devm_kzalloc(&rpdev->dev, sizeof(*pibus_pdrv), GFP_KERNEL);
            if (!pibus_pdrv){
                pr_err("pibus : failed to zalloc memory");
                return -ENOMEM;
            }
            
            dev_set_drvdata(&rpdev->dev, pibus_pdrv);
            pibus_pdrv->driver.name = "pibus";
            pibus_pdrv->driver.owner = THIS_MODULE;
            pibus_pdrv->driver.mod_name = KBUILD_MODNAME;
            pibus_pdrv->driver.of_match_table = pibus_of_id;
            pibus_pdrv->probe = pibus_platform_probe;
            pibus_pdrv->remove = pibus_platform_remove;
             
            ret = platform_driver_register(pibus_pdrv);
                if (ret){
                          pr_err("pibus : unable to register platform driver");
                          return ret;
                }
    
            return 0;
       }
    
  3. Registers the host device.

      pibushost = pi_core_register_host(&pdev->dev);
          if (IS_ERR(pibushost)) {
              dev_err(&pdev->dev, "Couldnt register pi-host\n");
              return -EINVAL;
          }
    
  4. Registers the child devices.

     ret = pi_core_register_devices(pibushost);
     if (ret){
         dev_err(&pdev->dev, "Couldnt register device\n");
         return ret;
     }
    
  5. Unregisters the host device when the driver is unloaded.

     static int pibus_platform_remove(struct platform_device *pdev)
      {
         struct pi_bus_host * pibushost;
         log_debug();
      
         pibushost = platform_get_drvdata(pdev);
         pi_core_unregister_host(pibushost);
        
         return 0;
      }
    

The RPMsg thing in the pi-bus.c source

The pi-bus driver is specific to the beaglebone black/green boards. The boards do not have a hardware parallel bus, but deploy the on SoC PRUs to act as a virtual parallel bus. On these boards, the PRUs are interfaced using a virtio-based RPMsg bus. To interface with the RPMsg bus, the driver needs to register itself as a rpmsg client driver, like the pi-bus driver does :

    static struct rpmsg_driver pi_bus_rpmsg_driver = {
           .drv.name	= KBUILD_MODNAME,
           .drv.owner	= THIS_MODULE,
           .id_table	= pi_bus_rpmsg_id,
           .probe		= pi_bus_rpmsg_probe,
           .remove		= pi_bus_rpmsg_remove,
     };
                    *
                    *
                    *
                    *
    ret = register_rpmsg_driver(&pi_bus_rpmsg_driver);
    if (ret) {
             pr_err("pi_bus: couldnt register bus type");
             return ret;
    }

And then implements the methods. The rpmsg associated prove method gets invoked only when the firmware booted on the PRUs create an rpmsg channel, with a channel name matching to the given id_table in the rpmsg client driver. The point to note here is that, the driver registers itself first as a rpmsg client driver and then, in the rpmsg probe function, as a platform driver. This basically means that to make pi-bus driver serve as a platform driver for the parallel interface bus, the PRUs need to be booted with the correct firmware.