11

I'm having trouble understanding how device-tree works, or specifically why this driver won't init. This is in the rockchip vendor kernel for android, version 3.10

drivers/watchdog/rk29_wdt.c (reduced for readability)

static const struct of_device_id of_rk29_wdt_match[] = {
    { .compatible = "rockchip,watch dog" }
};
static struct platform_driver rk29_wdt_driver = {
    .probe          = rk29_wdt_probe,
    [..]
            .of_match_table = of_rk29_wdt_match,
            .name   = "rk29-wdt",
    },
};

static int __init watchdog_init(void)
{ 
    printk("watchdog_init\n");
    return platform_driver_register(&rk29_wdt_driver);
}

and this is the soc dtsi

arch/arm/boot/dts/rk3288.dtsi

    watchdog: wdt@2004c000 {
            compatible = "rockchip,watch dog";
            reg = <0xff800000 0x100>;
            clocks = <&pclk_pd_alive>;
            clock-names = "pclk_wdt";
            interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
            rockchip,irq = <0>;
            rockchip,timeout = <2>;
            rockchip,atboot = <1>;
            rockchip,debug = <0>;
            status = "okay";
    };

however, the .probe function of the driver is never called. It is compiled in and the __init function is called. I suspect it has something to do witch the device tree entry not matching? Maybe the space is an issue?

Or is there anything else that runs before .probe that determines if the driver should continue?

Also i'm not sure how a flattened tree works, so maybe this is relevant:

arch/arm/mach-rockchip/rk3288

DT_MACHINE_START(RK3288_DT, "Rockchip RK3288 (Flattened Device Tree)")
    .smp            = smp_ops(rockchip_smp_ops),
    .map_io         = rk3288_dt_map_io,
    .init_time      = rk3288_dt_init_timer,
    .dt_compat      = rk3288_dt_compat,
    .init_late      = rk3288_init_late,
    .reserve        = rk3288_reserve,
    .restart        = rk3288_restart,
MACHINE_END
aep
  • 776
  • 5
  • 26
  • 1
    I'm assuming the real code's `of_rk29_wdt_match[]` initializer has a sentinel element at the end? It looks like it should match, assuming that space in the `"rockchip,watch dog"` really is a space in both the device tree and the driver. – Ian Abbott Feb 23 '16 at 17:11
  • 2
    It is unusual to have a space in the device name, though. I don't think I've seen that before. Does it work any better if you remove the space in both places (driver and device tree)? – Ian Abbott Feb 23 '16 at 17:13
  • 4
    Note that a .dtsi alone isn't _strictly_ sufficient to reason about - there _could_ be an overriding `status = "disabled";` in the board-level .dts, or the DTB could even be repainted by the bootloader. Personally I'd start by checking /proc/device-tree/ and blundering around /sys/ to figure out whether the DT node, the driver, and the device itself really are all present and correct, before getting into why the driver might not be binding to the device. – Notlikethat Feb 23 '16 at 23:18
  • 2
    Yes, my problem was that uboot was loading a totally different dtb and i wish i had known about /proc/device-tree and /sys/devices/platform, that's so useful. @Notlikethat could you convert your comment to an answer for future generations? – aep Feb 24 '16 at 15:05

2 Answers2

17

There are a number of possible ways this might happen, and most of them are well away from the driver code itself. Firstly, a .dtsi fragment alone doesn't tell the whole story - the device tree syntax is hierarchical, so the properties (in particular the status) might still be overridden by the board-level .dts which includes a basic SoC .dtsi file. Secondly, the compiled DTB isn't the last word either, since the bootloader may dynamically modify it before passing it to the kernel - this is typically done for memory nodes and SMP enable methods, but could potentially affect anything.

This kind of debugging is often best tackled in reverse, by examining the state of the booted system, then working backwards to figure out how things got that way - the specifics of this particular question rule some of this out already, but for the sake of completeness:

  • If the kernel knows about the driver, and it's loaded and properly initialised, it should show up somewhere in /sys/bus/*/drivers/ - otherwise, it may be in a module which needs loading, or it may have failed to initialise due to some unmet dependency on some other driver or resource.
  • If the kernel knows about the device, it should show up somewhere in /sys/bus/*/devices/, and if it's correctly bound to a driver and probed then they should both have a symlink to each other.
  • If the device is nowhere to be found, then on a DT-based system the next place to check would be /proc/device-tree/ (dependent on CONFIG_PROC_DEVICETREE on older kernels, and canonically found in /sys/firmware/devicetree/base/ on newer ones) - this will show the view of the DT as the kernel found it, and a bit of poking around there should hopefully make clear any missing nodes or out-of-place properties, such as a disabled node causing the kernel to skip creating a device altogether. Beware that the property files themselves are just the raw data - so you probably want to go snooping with hexdump rather than cat - and that all numeric cells are in big-endian byte order.
Notlikethat
  • 20,095
  • 3
  • 40
  • 77
0

I notice that in your definition you miss so called SENTINEL in your array, null empty struct. Look here an example:

static const struct of_device_id clk_ids[]  = {
{ .compatible = "sirf,atlas7-clkc" },
{},

};

Dražen G.
  • 358
  • 3
  • 10