Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * OF helpers for parsing display timings
0004  *
0005  * Copyright (c) 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>, Pengutronix
0006  *
0007  * based on of_videomode.c by Sascha Hauer <s.hauer@pengutronix.de>
0008  */
0009 #include <linux/export.h>
0010 #include <linux/of.h>
0011 #include <linux/slab.h>
0012 #include <video/display_timing.h>
0013 #include <video/of_display_timing.h>
0014 
0015 /**
0016  * parse_timing_property - parse timing_entry from device_node
0017  * @np: device_node with the property
0018  * @name: name of the property
0019  * @result: will be set to the return value
0020  *
0021  * DESCRIPTION:
0022  * Every display_timing can be specified with either just the typical value or
0023  * a range consisting of min/typ/max. This function helps handling this
0024  **/
0025 static int parse_timing_property(const struct device_node *np, const char *name,
0026               struct timing_entry *result)
0027 {
0028     struct property *prop;
0029     int length, cells, ret;
0030 
0031     prop = of_find_property(np, name, &length);
0032     if (!prop) {
0033         pr_err("%pOF: could not find property %s\n", np, name);
0034         return -EINVAL;
0035     }
0036 
0037     cells = length / sizeof(u32);
0038     if (cells == 1) {
0039         ret = of_property_read_u32(np, name, &result->typ);
0040         result->min = result->typ;
0041         result->max = result->typ;
0042     } else if (cells == 3) {
0043         ret = of_property_read_u32_array(np, name, &result->min, cells);
0044     } else {
0045         pr_err("%pOF: illegal timing specification in %s\n", np, name);
0046         return -EINVAL;
0047     }
0048 
0049     return ret;
0050 }
0051 
0052 /**
0053  * of_parse_display_timing - parse display_timing entry from device_node
0054  * @np: device_node with the properties
0055  * @dt: display_timing that contains the result. I may be partially written in case of errors
0056  **/
0057 static int of_parse_display_timing(const struct device_node *np,
0058         struct display_timing *dt)
0059 {
0060     u32 val = 0;
0061     int ret = 0;
0062 
0063     memset(dt, 0, sizeof(*dt));
0064 
0065     ret |= parse_timing_property(np, "hback-porch", &dt->hback_porch);
0066     ret |= parse_timing_property(np, "hfront-porch", &dt->hfront_porch);
0067     ret |= parse_timing_property(np, "hactive", &dt->hactive);
0068     ret |= parse_timing_property(np, "hsync-len", &dt->hsync_len);
0069     ret |= parse_timing_property(np, "vback-porch", &dt->vback_porch);
0070     ret |= parse_timing_property(np, "vfront-porch", &dt->vfront_porch);
0071     ret |= parse_timing_property(np, "vactive", &dt->vactive);
0072     ret |= parse_timing_property(np, "vsync-len", &dt->vsync_len);
0073     ret |= parse_timing_property(np, "clock-frequency", &dt->pixelclock);
0074 
0075     dt->flags = 0;
0076     if (!of_property_read_u32(np, "vsync-active", &val))
0077         dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
0078                 DISPLAY_FLAGS_VSYNC_LOW;
0079     if (!of_property_read_u32(np, "hsync-active", &val))
0080         dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
0081                 DISPLAY_FLAGS_HSYNC_LOW;
0082     if (!of_property_read_u32(np, "de-active", &val))
0083         dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
0084                 DISPLAY_FLAGS_DE_LOW;
0085     if (!of_property_read_u32(np, "pixelclk-active", &val))
0086         dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
0087                 DISPLAY_FLAGS_PIXDATA_NEGEDGE;
0088 
0089     if (!of_property_read_u32(np, "syncclk-active", &val))
0090         dt->flags |= val ? DISPLAY_FLAGS_SYNC_POSEDGE :
0091                 DISPLAY_FLAGS_SYNC_NEGEDGE;
0092     else if (dt->flags & (DISPLAY_FLAGS_PIXDATA_POSEDGE |
0093                   DISPLAY_FLAGS_PIXDATA_NEGEDGE))
0094         dt->flags |= dt->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE ?
0095                 DISPLAY_FLAGS_SYNC_POSEDGE :
0096                 DISPLAY_FLAGS_SYNC_NEGEDGE;
0097 
0098     if (of_property_read_bool(np, "interlaced"))
0099         dt->flags |= DISPLAY_FLAGS_INTERLACED;
0100     if (of_property_read_bool(np, "doublescan"))
0101         dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
0102     if (of_property_read_bool(np, "doubleclk"))
0103         dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
0104 
0105     if (ret) {
0106         pr_err("%pOF: error reading timing properties\n", np);
0107         return -EINVAL;
0108     }
0109 
0110     return 0;
0111 }
0112 
0113 /**
0114  * of_get_display_timing - parse a display_timing entry
0115  * @np: device_node with the timing subnode
0116  * @name: name of the timing node
0117  * @dt: display_timing struct to fill
0118  **/
0119 int of_get_display_timing(const struct device_node *np, const char *name,
0120         struct display_timing *dt)
0121 {
0122     struct device_node *timing_np;
0123     int ret;
0124 
0125     if (!np)
0126         return -EINVAL;
0127 
0128     timing_np = of_get_child_by_name(np, name);
0129     if (!timing_np)
0130         return -ENOENT;
0131 
0132     ret = of_parse_display_timing(timing_np, dt);
0133 
0134     of_node_put(timing_np);
0135 
0136     return ret;
0137 }
0138 EXPORT_SYMBOL_GPL(of_get_display_timing);
0139 
0140 /**
0141  * of_get_display_timings - parse all display_timing entries from a device_node
0142  * @np: device_node with the subnodes
0143  **/
0144 struct display_timings *of_get_display_timings(const struct device_node *np)
0145 {
0146     struct device_node *timings_np;
0147     struct device_node *entry;
0148     struct device_node *native_mode;
0149     struct display_timings *disp;
0150 
0151     if (!np)
0152         return NULL;
0153 
0154     timings_np = of_get_child_by_name(np, "display-timings");
0155     if (!timings_np) {
0156         pr_err("%pOF: could not find display-timings node\n", np);
0157         return NULL;
0158     }
0159 
0160     disp = kzalloc(sizeof(*disp), GFP_KERNEL);
0161     if (!disp) {
0162         pr_err("%pOF: could not allocate struct disp'\n", np);
0163         goto dispfail;
0164     }
0165 
0166     entry = of_parse_phandle(timings_np, "native-mode", 0);
0167     /* assume first child as native mode if none provided */
0168     if (!entry)
0169         entry = of_get_next_child(timings_np, NULL);
0170     /* if there is no child, it is useless to go on */
0171     if (!entry) {
0172         pr_err("%pOF: no timing specifications given\n", np);
0173         goto entryfail;
0174     }
0175 
0176     pr_debug("%pOF: using %pOFn as default timing\n", np, entry);
0177 
0178     native_mode = entry;
0179 
0180     disp->num_timings = of_get_child_count(timings_np);
0181     if (disp->num_timings == 0) {
0182         /* should never happen, as entry was already found above */
0183         pr_err("%pOF: no timings specified\n", np);
0184         goto entryfail;
0185     }
0186 
0187     disp->timings = kcalloc(disp->num_timings,
0188                 sizeof(struct display_timing *),
0189                 GFP_KERNEL);
0190     if (!disp->timings) {
0191         pr_err("%pOF: could not allocate timings array\n", np);
0192         goto entryfail;
0193     }
0194 
0195     disp->num_timings = 0;
0196     disp->native_mode = 0;
0197 
0198     for_each_child_of_node(timings_np, entry) {
0199         struct display_timing *dt;
0200         int r;
0201 
0202         dt = kmalloc(sizeof(*dt), GFP_KERNEL);
0203         if (!dt) {
0204             pr_err("%pOF: could not allocate display_timing struct\n",
0205                 np);
0206             goto timingfail;
0207         }
0208 
0209         r = of_parse_display_timing(entry, dt);
0210         if (r) {
0211             /*
0212              * to not encourage wrong devicetrees, fail in case of
0213              * an error
0214              */
0215             pr_err("%pOF: error in timing %d\n",
0216                 np, disp->num_timings + 1);
0217             kfree(dt);
0218             goto timingfail;
0219         }
0220 
0221         if (native_mode == entry)
0222             disp->native_mode = disp->num_timings;
0223 
0224         disp->timings[disp->num_timings] = dt;
0225         disp->num_timings++;
0226     }
0227     of_node_put(timings_np);
0228     /*
0229      * native_mode points to the device_node returned by of_parse_phandle
0230      * therefore call of_node_put on it
0231      */
0232     of_node_put(native_mode);
0233 
0234     pr_debug("%pOF: got %d timings. Using timing #%d as default\n",
0235         np, disp->num_timings,
0236         disp->native_mode + 1);
0237 
0238     return disp;
0239 
0240 timingfail:
0241     of_node_put(native_mode);
0242     display_timings_release(disp);
0243     disp = NULL;
0244 entryfail:
0245     kfree(disp);
0246 dispfail:
0247     of_node_put(timings_np);
0248     return NULL;
0249 }
0250 EXPORT_SYMBOL_GPL(of_get_display_timings);