X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=drivers%2Fvideo%2Fof_display_timing.c;h=e393412faf6637788222a4e3f3c8adf473644c62;hb=83fb4e1f93adb50a1c90d1554e72a0d64ce6eb57;hp=56009bc02b02475b525966ee9b8239d4a779b56d;hpb=240e7f3ebf06fc651deeb75ea4721796f701b9af;p=firefly-linux-kernel-4.4.55.git diff --git a/drivers/video/of_display_timing.c b/drivers/video/of_display_timing.c index 56009bc02b02..e393412faf66 100644 --- a/drivers/video/of_display_timing.c +++ b/drivers/video/of_display_timing.c @@ -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: