linux/drivers/video/of_display_timing.c
<<
>>
Prefs
   1/*
   2 * OF helpers for parsing display timings
   3 *
   4 * Copyright (c) 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>, Pengutronix
   5 *
   6 * based on of_videomode.c by Sascha Hauer <s.hauer@pengutronix.de>
   7 *
   8 * This file is released under the GPLv2
   9 */
  10#include <linux/export.h>
  11#include <linux/of.h>
  12#include <linux/slab.h>
  13#include <video/display_timing.h>
  14#include <video/of_display_timing.h>
  15
  16/**
  17 * parse_timing_property - parse timing_entry from device_node
  18 * @np: device_node with the property
  19 * @name: name of the property
  20 * @result: will be set to the return value
  21 *
  22 * DESCRIPTION:
  23 * Every display_timing can be specified with either just the typical value or
  24 * a range consisting of min/typ/max. This function helps handling this
  25 **/
  26static int parse_timing_property(struct device_node *np, const char *name,
  27                          struct timing_entry *result)
  28{
  29        struct property *prop;
  30        int length, cells, ret;
  31
  32        prop = of_find_property(np, name, &length);
  33        if (!prop) {
  34                pr_err("%s: could not find property %s\n",
  35                        of_node_full_name(np), name);
  36                return -EINVAL;
  37        }
  38
  39        cells = length / sizeof(u32);
  40        if (cells == 1) {
  41                ret = of_property_read_u32(np, name, &result->typ);
  42                result->min = result->typ;
  43                result->max = result->typ;
  44        } else if (cells == 3) {
  45                ret = of_property_read_u32_array(np, name, &result->min, cells);
  46        } else {
  47                pr_err("%s: illegal timing specification in %s\n",
  48                        of_node_full_name(np), name);
  49                return -EINVAL;
  50        }
  51
  52        return ret;
  53}
  54
  55/**
  56 * of_get_display_timing - parse display_timing entry from device_node
  57 * @np: device_node with the properties
  58 **/
  59static struct display_timing *of_get_display_timing(struct device_node *np)
  60{
  61        struct display_timing *dt;
  62        u32 val = 0;
  63        int ret = 0;
  64
  65        dt = kzalloc(sizeof(*dt), GFP_KERNEL);
  66        if (!dt) {
  67                pr_err("%s: could not allocate display_timing struct\n",
  68                        of_node_full_name(np));
  69                return NULL;
  70        }
  71
  72        ret |= parse_timing_property(np, "hback-porch", &dt->hback_porch);
  73        ret |= parse_timing_property(np, "hfront-porch", &dt->hfront_porch);
  74        ret |= parse_timing_property(np, "hactive", &dt->hactive);
  75        ret |= parse_timing_property(np, "hsync-len", &dt->hsync_len);
  76        ret |= parse_timing_property(np, "vback-porch", &dt->vback_porch);
  77        ret |= parse_timing_property(np, "vfront-porch", &dt->vfront_porch);
  78        ret |= parse_timing_property(np, "vactive", &dt->vactive);
  79        ret |= parse_timing_property(np, "vsync-len", &dt->vsync_len);
  80        ret |= parse_timing_property(np, "clock-frequency", &dt->pixelclock);
  81
  82        dt->dmt_flags = 0;
  83        dt->data_flags = 0;
  84        if (!of_property_read_u32(np, "vsync-active", &val))
  85                dt->dmt_flags |= val ? VESA_DMT_VSYNC_HIGH :
  86                                VESA_DMT_VSYNC_LOW;
  87        if (!of_property_read_u32(np, "hsync-active", &val))
  88                dt->dmt_flags |= val ? VESA_DMT_HSYNC_HIGH :
  89                                VESA_DMT_HSYNC_LOW;
  90        if (!of_property_read_u32(np, "de-active", &val))
  91                dt->data_flags |= val ? DISPLAY_FLAGS_DE_HIGH :
  92                                DISPLAY_FLAGS_DE_LOW;
  93        if (!of_property_read_u32(np, "pixelclk-active", &val))
  94                dt->data_flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
  95                                DISPLAY_FLAGS_PIXDATA_NEGEDGE;
  96
  97        if (of_property_read_bool(np, "interlaced"))
  98                dt->data_flags |= DISPLAY_FLAGS_INTERLACED;
  99        if (of_property_read_bool(np, "doublescan"))
 100                dt->data_flags |= DISPLAY_FLAGS_DOUBLESCAN;
 101
 102        if (ret) {
 103                pr_err("%s: error reading timing properties\n",
 104                        of_node_full_name(np));
 105                kfree(dt);
 106                return NULL;
 107        }
 108
 109        return dt;
 110}
 111
 112/**
 113 * of_get_display_timings - parse all display_timing entries from a device_node
 114 * @np: device_node with the subnodes
 115 **/
 116struct display_timings *of_get_display_timings(struct device_node *np)
 117{
 118        struct device_node *timings_np;
 119        struct device_node *entry;
 120        struct device_node *native_mode;
 121        struct display_timings *disp;
 122
 123        if (!np) {
 124                pr_err("%s: no devicenode given\n", of_node_full_name(np));
 125                return NULL;
 126        }
 127
 128        timings_np = of_find_node_by_name(np, "display-timings");
 129        if (!timings_np) {
 130                pr_err("%s: could not find display-timings node\n",
 131                        of_node_full_name(np));
 132                return NULL;
 133        }
 134
 135        disp = kzalloc(sizeof(*disp), GFP_KERNEL);
 136        if (!disp) {
 137                pr_err("%s: could not allocate struct disp'\n",
 138                        of_node_full_name(np));
 139                goto dispfail;
 140        }
 141
 142        entry = of_parse_phandle(timings_np, "native-mode", 0);
 143        /* assume first child as native mode if none provided */
 144        if (!entry)
 145                entry = of_get_next_child(np, NULL);
 146        /* if there is no child, it is useless to go on */
 147        if (!entry) {
 148                pr_err("%s: no timing specifications given\n",
 149                        of_node_full_name(np));
 150                goto entryfail;
 151        }
 152
 153        pr_debug("%s: using %s as default timing\n",
 154                of_node_full_name(np), entry->name);
 155
 156        native_mode = entry;
 157
 158        disp->num_timings = of_get_child_count(timings_np);
 159        if (disp->num_timings == 0) {
 160                /* should never happen, as entry was already found above */
 161                pr_err("%s: no timings specified\n", of_node_full_name(np));
 162                goto entryfail;
 163        }
 164
 165        disp->timings = kzalloc(sizeof(struct display_timing *) *
 166                                disp->num_timings, GFP_KERNEL);
 167        if (!disp->timings) {
 168                pr_err("%s: could not allocate timings array\n",
 169                        of_node_full_name(np));
 170                goto entryfail;
 171        }
 172
 173        disp->num_timings = 0;
 174        disp->native_mode = 0;
 175
 176        for_each_child_of_node(timings_np, entry) {
 177                struct display_timing *dt;
 178
 179                dt = of_get_display_timing(entry);
 180                if (!dt) {
 181                        /*
 182                         * to not encourage wrong devicetrees, fail in case of
 183                         * an error
 184                         */
 185                        pr_err("%s: error in timing %d\n",
 186                                of_node_full_name(np), disp->num_timings + 1);
 187                        goto timingfail;
 188                }
 189
 190                if (native_mode == entry)
 191                        disp->native_mode = disp->num_timings;
 192
 193                disp->timings[disp->num_timings] = dt;
 194                disp->num_timings++;
 195        }
 196        of_node_put(timings_np);
 197        /*
 198         * native_mode points to the device_node returned by of_parse_phandle
 199         * therefore call of_node_put on it
 200         */
 201        of_node_put(native_mode);
 202
 203        pr_debug("%s: got %d timings. Using timing #%d as default\n",
 204                of_node_full_name(np), disp->num_timings,
 205                disp->native_mode + 1);
 206
 207        return disp;
 208
 209timingfail:
 210        if (native_mode)
 211                of_node_put(native_mode);
 212        display_timings_release(disp);
 213entryfail:
 214        kfree(disp);
 215dispfail:
 216        of_node_put(timings_np);
 217        return NULL;
 218}
 219EXPORT_SYMBOL_GPL(of_get_display_timings);
 220
 221/**
 222 * of_display_timings_exist - check if a display-timings node is provided
 223 * @np: device_node with the timing
 224 **/
 225int of_display_timings_exist(struct device_node *np)
 226{
 227        struct device_node *timings_np;
 228
 229        if (!np)
 230                return -EINVAL;
 231
 232        timings_np = of_parse_phandle(np, "display-timings", 0);
 233        if (!timings_np)
 234                return -EINVAL;
 235
 236        of_node_put(timings_np);
 237        return 1;
 238}
 239EXPORT_SYMBOL_GPL(of_display_timings_exist);
 240