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->flags = 0;
  83        if (!of_property_read_u32(np, "vsync-active", &val))
  84                dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
  85                                DISPLAY_FLAGS_VSYNC_LOW;
  86        if (!of_property_read_u32(np, "hsync-active", &val))
  87                dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
  88                                DISPLAY_FLAGS_HSYNC_LOW;
  89        if (!of_property_read_u32(np, "de-active", &val))
  90                dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
  91                                DISPLAY_FLAGS_DE_LOW;
  92        if (!of_property_read_u32(np, "pixelclk-active", &val))
  93                dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
  94                                DISPLAY_FLAGS_PIXDATA_NEGEDGE;
  95
  96        if (of_property_read_bool(np, "interlaced"))
  97                dt->flags |= DISPLAY_FLAGS_INTERLACED;
  98        if (of_property_read_bool(np, "doublescan"))
  99                dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
 100
 101        if (ret) {
 102                pr_err("%s: error reading timing properties\n",
 103                        of_node_full_name(np));
 104                kfree(dt);
 105                return NULL;
 106        }
 107
 108        return dt;
 109}
 110
 111/**
 112 * of_get_display_timings - parse all display_timing entries from a device_node
 113 * @np: device_node with the subnodes
 114 **/
 115struct display_timings *of_get_display_timings(struct device_node *np)
 116{
 117        struct device_node *timings_np;
 118        struct device_node *entry;
 119        struct device_node *native_mode;
 120        struct display_timings *disp;
 121
 122        if (!np) {
 123                pr_err("%s: no devicenode given\n", of_node_full_name(np));
 124                return NULL;
 125        }
 126
 127        timings_np = of_find_node_by_name(np, "display-timings");
 128        if (!timings_np) {
 129                pr_err("%s: could not find display-timings node\n",
 130                        of_node_full_name(np));
 131                return NULL;
 132        }
 133
 134        disp = kzalloc(sizeof(*disp), GFP_KERNEL);
 135        if (!disp) {
 136                pr_err("%s: could not allocate struct disp'\n",
 137                        of_node_full_name(np));
 138                goto dispfail;
 139        }
 140
 141        entry = of_parse_phandle(timings_np, "native-mode", 0);
 142        /* assume first child as native mode if none provided */
 143        if (!entry)
 144                entry = of_get_next_child(np, NULL);
 145        /* if there is no child, it is useless to go on */
 146        if (!entry) {
 147                pr_err("%s: no timing specifications given\n",
 148                        of_node_full_name(np));
 149                goto entryfail;
 150        }
 151
 152        pr_debug("%s: using %s as default timing\n",
 153                of_node_full_name(np), entry->name);
 154
 155        native_mode = entry;
 156
 157        disp->num_timings = of_get_child_count(timings_np);
 158        if (disp->num_timings == 0) {
 159                /* should never happen, as entry was already found above */
 160                pr_err("%s: no timings specified\n", of_node_full_name(np));
 161                goto entryfail;
 162        }
 163
 164        disp->timings = kzalloc(sizeof(struct display_timing *) *
 165                                disp->num_timings, GFP_KERNEL);
 166        if (!disp->timings) {
 167                pr_err("%s: could not allocate timings array\n",
 168                        of_node_full_name(np));
 169                goto entryfail;
 170        }
 171
 172        disp->num_timings = 0;
 173        disp->native_mode = 0;
 174
 175        for_each_child_of_node(timings_np, entry) {
 176                struct display_timing *dt;
 177
 178                dt = of_get_display_timing(entry);
 179                if (!dt) {
 180                        /*
 181                         * to not encourage wrong devicetrees, fail in case of
 182                         * an error
 183                         */
 184                        pr_err("%s: error in timing %d\n",
 185                                of_node_full_name(np), disp->num_timings + 1);
 186                        goto timingfail;
 187                }
 188
 189                if (native_mode == entry)
 190                        disp->native_mode = disp->num_timings;
 191
 192                disp->timings[disp->num_timings] = dt;
 193                disp->num_timings++;
 194        }
 195        of_node_put(timings_np);
 196        /*
 197         * native_mode points to the device_node returned by of_parse_phandle
 198         * therefore call of_node_put on it
 199         */
 200        of_node_put(native_mode);
 201
 202        pr_debug("%s: got %d timings. Using timing #%d as default\n",
 203                of_node_full_name(np), disp->num_timings,
 204                disp->native_mode + 1);
 205
 206        return disp;
 207
 208timingfail:
 209        if (native_mode)
 210                of_node_put(native_mode);
 211        display_timings_release(disp);
 212entryfail:
 213        kfree(disp);
 214dispfail:
 215        of_node_put(timings_np);
 216        return NULL;
 217}
 218EXPORT_SYMBOL_GPL(of_get_display_timings);
 219
 220/**
 221 * of_display_timings_exist - check if a display-timings node is provided
 222 * @np: device_node with the timing
 223 **/
 224int of_display_timings_exist(struct device_node *np)
 225{
 226        struct device_node *timings_np;
 227
 228        if (!np)
 229                return -EINVAL;
 230
 231        timings_np = of_parse_phandle(np, "display-timings", 0);
 232        if (!timings_np)
 233                return -EINVAL;
 234
 235        of_node_put(timings_np);
 236        return 1;
 237}
 238EXPORT_SYMBOL_GPL(of_display_timings_exist);
 239
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.