* 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;
}
/**
- * 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);
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
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));
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",
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;
}
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: