thermal: rockchip: add temperature dump when panic
[firefly-linux-kernel-4.4.55.git] / drivers / video / of_display_timing.c
index 56009bc02b02475b525966ee9b8239d4a779b56d..e393412faf6637788222a4e3f3c8adf473644c62 100644 (file)
@@ -23,7 +23,7 @@
  * Every display_timing can be specified with either just the typical value or
  * a range consisting of min/typ/max. This function helps handling this
  **/
-static int parse_timing_property(struct device_node *np, const char *name,
+static int parse_timing_property(const struct device_node *np, const char *name,
                          struct timing_entry *result)
 {
        struct property *prop;
@@ -53,21 +53,20 @@ static int parse_timing_property(struct device_node *np, const char *name,
 }
 
 /**
- * of_get_display_timing - parse display_timing entry from device_node
+ * of_parse_display_timing - parse display_timing entry from device_node
  * @np: device_node with the properties
  **/
-static struct display_timing *of_get_display_timing(struct device_node *np)
+static int of_parse_display_timing(const struct device_node *np,
+               struct display_timing *dt)
 {
-       struct display_timing *dt;
        u32 val = 0;
        int ret = 0;
+#if defined(CONFIG_FB_ROCKCHIP)
+       struct property *prop;
+       int length;
+#endif
 
-       dt = kzalloc(sizeof(*dt), GFP_KERNEL);
-       if (!dt) {
-               pr_err("%s: could not allocate display_timing struct\n",
-                       of_node_full_name(np));
-               return NULL;
-       }
+       memset(dt, 0, sizeof(*dt));
 
        ret |= parse_timing_property(np, "hback-porch", &dt->hback_porch);
        ret |= parse_timing_property(np, "hfront-porch", &dt->hfront_porch);
@@ -97,16 +96,88 @@ static struct display_timing *of_get_display_timing(struct device_node *np)
                dt->flags |= DISPLAY_FLAGS_INTERLACED;
        if (of_property_read_bool(np, "doublescan"))
                dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
+       if (of_property_read_bool(np, "doubleclk"))
+               dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
+#if defined(CONFIG_FB_ROCKCHIP)
+       if (!of_property_read_u32(np, "swap-rg", &val))
+               dt->flags |= val ? DISPLAY_FLAGS_SWAP_RG : 0;
+       if (!of_property_read_u32(np, "swap-gb", &val))
+               dt->flags |= val ? DISPLAY_FLAGS_SWAP_GB : 0;
+       if (!of_property_read_u32(np, "swap-rb", &val))
+               dt->flags |= val ? DISPLAY_FLAGS_SWAP_RB : 0;
+       if (!of_property_read_u32(np, "screen-type", &val))
+               dt->screen_type = val;
+       if (!of_property_read_u32(np, "lvds-format", &val))
+               dt->lvds_format = val;
+       if (!of_property_read_u32(np, "out-face", &val))
+               dt->face = val;
+       if (!of_property_read_u32(np, "color-mode", &val))
+                dt->color_mode = val;
+       if (!of_property_read_u32(np, "screen-width", &val))
+                dt->screen_widt = val;
+       if (!of_property_read_u32(np, "screen-hight", &val))
+                dt->screen_hight = val;
+       prop = of_find_property(np, "dsp-lut", &length);
+       if (prop) {
+               dt->dsp_lut = kzalloc(length, GFP_KERNEL);
+               if (dt->dsp_lut)
+                       ret = of_property_read_u32_array(np,
+                               "dsp-lut", dt->dsp_lut, length >> 2);
+       }
+       prop = of_find_property(np, "cabc-lut", &length);
+       if (prop) {
+               dt->cabc_lut = kzalloc(length, GFP_KERNEL);
+               if (dt->cabc_lut)
+                       ret = of_property_read_u32_array(np,
+                                                        "cabc-lut",
+                                                        dt->cabc_lut,
+                                                        length >> 2);
+       }
+
+       prop = of_find_property(np, "cabc-gamma-base", &length);
+       if (prop) {
+               dt->cabc_gamma_base = kzalloc(length, GFP_KERNEL);
+               if (dt->cabc_gamma_base)
+                       ret = of_property_read_u32_array(np,
+                                                        "cabc-gamma-base",
+                                                        dt->cabc_gamma_base,
+                                                        length >> 2);
+       }
+#endif
 
        if (ret) {
                pr_err("%s: error reading timing properties\n",
                        of_node_full_name(np));
-               kfree(dt);
-               return NULL;
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * of_get_display_timing - parse a display_timing entry
+ * @np: device_node with the timing subnode
+ * @name: name of the timing node
+ * @dt: display_timing struct to fill
+ **/
+int of_get_display_timing(struct device_node *np, const char *name,
+               struct display_timing *dt)
+{
+       struct device_node *timing_np;
+
+       if (!np)
+               return -EINVAL;
+
+       timing_np = of_get_child_by_name(np, name);
+       if (!timing_np) {
+               pr_err("%s: could not find node '%s'\n",
+                       of_node_full_name(np), name);
+               return -ENOENT;
        }
 
-       return dt;
+       return of_parse_display_timing(timing_np, dt);
 }
+EXPORT_SYMBOL_GPL(of_get_display_timing);
 
 /**
  * of_get_display_timings - parse all display_timing entries from a device_node
@@ -119,12 +190,10 @@ struct display_timings *of_get_display_timings(struct device_node *np)
        struct device_node *native_mode;
        struct display_timings *disp;
 
-       if (!np) {
-               pr_err("%s: no devicenode given\n", of_node_full_name(np));
+       if (!np)
                return NULL;
-       }
 
-       timings_np = of_find_node_by_name(np, "display-timings");
+       timings_np = of_get_child_by_name(np, "display-timings");
        if (!timings_np) {
                pr_err("%s: could not find display-timings node\n",
                        of_node_full_name(np));
@@ -141,7 +210,7 @@ struct display_timings *of_get_display_timings(struct device_node *np)
        entry = of_parse_phandle(timings_np, "native-mode", 0);
        /* assume first child as native mode if none provided */
        if (!entry)
-               entry = of_get_next_child(np, NULL);
+               entry = of_get_next_child(timings_np, NULL);
        /* if there is no child, it is useless to go on */
        if (!entry) {
                pr_err("%s: no timing specifications given\n",
@@ -174,15 +243,24 @@ struct display_timings *of_get_display_timings(struct device_node *np)
 
        for_each_child_of_node(timings_np, entry) {
                struct display_timing *dt;
+               int r;
 
-               dt = of_get_display_timing(entry);
+               dt = kzalloc(sizeof(*dt), GFP_KERNEL);
                if (!dt) {
+                       pr_err("%s: could not allocate display_timing struct\n",
+                                       of_node_full_name(np));
+                       goto timingfail;
+               }
+
+               r = of_parse_display_timing(entry, dt);
+               if (r) {
                        /*
                         * to not encourage wrong devicetrees, fail in case of
                         * an error
                         */
                        pr_err("%s: error in timing %d\n",
                                of_node_full_name(np), disp->num_timings + 1);
+                       kfree(dt);
                        goto timingfail;
                }
 
@@ -206,9 +284,9 @@ struct display_timings *of_get_display_timings(struct device_node *np)
        return disp;
 
 timingfail:
-       if (native_mode)
-               of_node_put(native_mode);
+       of_node_put(native_mode);
        display_timings_release(disp);
+       disp = NULL;
 entryfail:
        kfree(disp);
 dispfail: