brintos

brintos / linux-shallow public Read only

0
0
Text · 6.7 KiB · bebd371 Raw
251 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * OF helpers for parsing display timings4 *5 * Copyright (c) 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>, Pengutronix6 *7 * based on of_videomode.c by Sascha Hauer <s.hauer@pengutronix.de>8 */9#include <linux/export.h>10#include <linux/of.h>11#include <linux/slab.h>12#include <video/display_timing.h>13#include <video/of_display_timing.h>14 15/**16 * parse_timing_property - parse timing_entry from device_node17 * @np: device_node with the property18 * @name: name of the property19 * @result: will be set to the return value20 *21 * DESCRIPTION:22 * Every display_timing can be specified with either just the typical value or23 * a range consisting of min/typ/max. This function helps handling this24 **/25static int parse_timing_property(const struct device_node *np, const char *name,26			  struct timing_entry *result)27{28	struct property *prop;29	int length, cells, ret;30 31	prop = of_find_property(np, name, &length);32	if (!prop) {33		pr_err("%pOF: could not find property %s\n", np, name);34		return -EINVAL;35	}36 37	cells = length / sizeof(u32);38	if (cells == 1) {39		ret = of_property_read_u32(np, name, &result->typ);40		result->min = result->typ;41		result->max = result->typ;42	} else if (cells == 3) {43		ret = of_property_read_u32_array(np, name, &result->min, cells);44	} else {45		pr_err("%pOF: illegal timing specification in %s\n", np, name);46		return -EINVAL;47	}48 49	return ret;50}51 52/**53 * of_parse_display_timing - parse display_timing entry from device_node54 * @np: device_node with the properties55 * @dt: display_timing that contains the result. I may be partially written in case of errors56 **/57static int of_parse_display_timing(const struct device_node *np,58		struct display_timing *dt)59{60	u32 val = 0;61	int ret = 0;62 63	memset(dt, 0, sizeof(*dt));64 65	ret |= parse_timing_property(np, "hback-porch", &dt->hback_porch);66	ret |= parse_timing_property(np, "hfront-porch", &dt->hfront_porch);67	ret |= parse_timing_property(np, "hactive", &dt->hactive);68	ret |= parse_timing_property(np, "hsync-len", &dt->hsync_len);69	ret |= parse_timing_property(np, "vback-porch", &dt->vback_porch);70	ret |= parse_timing_property(np, "vfront-porch", &dt->vfront_porch);71	ret |= parse_timing_property(np, "vactive", &dt->vactive);72	ret |= parse_timing_property(np, "vsync-len", &dt->vsync_len);73	ret |= parse_timing_property(np, "clock-frequency", &dt->pixelclock);74 75	dt->flags = 0;76	if (!of_property_read_u32(np, "vsync-active", &val))77		dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :78				DISPLAY_FLAGS_VSYNC_LOW;79	if (!of_property_read_u32(np, "hsync-active", &val))80		dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :81				DISPLAY_FLAGS_HSYNC_LOW;82	if (!of_property_read_u32(np, "de-active", &val))83		dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :84				DISPLAY_FLAGS_DE_LOW;85	if (!of_property_read_u32(np, "pixelclk-active", &val))86		dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :87				DISPLAY_FLAGS_PIXDATA_NEGEDGE;88 89	if (!of_property_read_u32(np, "syncclk-active", &val))90		dt->flags |= val ? DISPLAY_FLAGS_SYNC_POSEDGE :91				DISPLAY_FLAGS_SYNC_NEGEDGE;92	else if (dt->flags & (DISPLAY_FLAGS_PIXDATA_POSEDGE |93			      DISPLAY_FLAGS_PIXDATA_NEGEDGE))94		dt->flags |= dt->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE ?95				DISPLAY_FLAGS_SYNC_POSEDGE :96				DISPLAY_FLAGS_SYNC_NEGEDGE;97 98	if (of_property_read_bool(np, "interlaced"))99		dt->flags |= DISPLAY_FLAGS_INTERLACED;100	if (of_property_read_bool(np, "doublescan"))101		dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;102	if (of_property_read_bool(np, "doubleclk"))103		dt->flags |= DISPLAY_FLAGS_DOUBLECLK;104 105	if (ret) {106		pr_err("%pOF: error reading timing properties\n", np);107		return -EINVAL;108	}109 110	return 0;111}112 113/**114 * of_get_display_timing - parse a display_timing entry115 * @np: device_node with the timing subnode116 * @name: name of the timing node117 * @dt: display_timing struct to fill118 **/119int of_get_display_timing(const struct device_node *np, const char *name,120		struct display_timing *dt)121{122	struct device_node *timing_np;123	int ret;124 125	if (!np)126		return -EINVAL;127 128	timing_np = of_get_child_by_name(np, name);129	if (!timing_np)130		return -ENOENT;131 132	ret = of_parse_display_timing(timing_np, dt);133 134	of_node_put(timing_np);135 136	return ret;137}138EXPORT_SYMBOL_GPL(of_get_display_timing);139 140/**141 * of_get_display_timings - parse all display_timing entries from a device_node142 * @np: device_node with the subnodes143 **/144struct display_timings *of_get_display_timings(const struct device_node *np)145{146	struct device_node *timings_np;147	struct device_node *entry;148	struct device_node *native_mode;149	struct display_timings *disp;150 151	if (!np)152		return NULL;153 154	timings_np = of_get_child_by_name(np, "display-timings");155	if (!timings_np) {156		pr_err("%pOF: could not find display-timings node\n", np);157		return NULL;158	}159 160	disp = kzalloc(sizeof(*disp), GFP_KERNEL);161	if (!disp) {162		pr_err("%pOF: could not allocate struct disp'\n", np);163		goto dispfail;164	}165 166	entry = of_parse_phandle(timings_np, "native-mode", 0);167	/* assume first child as native mode if none provided */168	if (!entry)169		entry = of_get_next_child(timings_np, NULL);170	/* if there is no child, it is useless to go on */171	if (!entry) {172		pr_err("%pOF: no timing specifications given\n", np);173		goto entryfail;174	}175 176	pr_debug("%pOF: using %pOFn as default timing\n", np, entry);177 178	native_mode = entry;179 180	disp->num_timings = of_get_child_count(timings_np);181	if (disp->num_timings == 0) {182		/* should never happen, as entry was already found above */183		pr_err("%pOF: no timings specified\n", np);184		goto entryfail;185	}186 187	disp->timings = kcalloc(disp->num_timings,188				sizeof(struct display_timing *),189				GFP_KERNEL);190	if (!disp->timings) {191		pr_err("%pOF: could not allocate timings array\n", np);192		goto entryfail;193	}194 195	disp->num_timings = 0;196	disp->native_mode = 0;197 198	for_each_child_of_node(timings_np, entry) {199		struct display_timing *dt;200		int r;201 202		dt = kmalloc(sizeof(*dt), GFP_KERNEL);203		if (!dt) {204			pr_err("%pOF: could not allocate display_timing struct\n",205				np);206			goto timingfail;207		}208 209		r = of_parse_display_timing(entry, dt);210		if (r) {211			/*212			 * to not encourage wrong devicetrees, fail in case of213			 * an error214			 */215			pr_err("%pOF: error in timing %d\n",216				np, disp->num_timings + 1);217			kfree(dt);218			goto timingfail;219		}220 221		if (native_mode == entry)222			disp->native_mode = disp->num_timings;223 224		disp->timings[disp->num_timings] = dt;225		disp->num_timings++;226	}227	of_node_put(timings_np);228	/*229	 * native_mode points to the device_node returned by of_parse_phandle230	 * therefore call of_node_put on it231	 */232	of_node_put(native_mode);233 234	pr_debug("%pOF: got %d timings. Using timing #%d as default\n",235		np, disp->num_timings,236		disp->native_mode + 1);237 238	return disp;239 240timingfail:241	of_node_put(native_mode);242	display_timings_release(disp);243	disp = NULL;244entryfail:245	kfree(disp);246dispfail:247	of_node_put(timings_np);248	return NULL;249}250EXPORT_SYMBOL_GPL(of_get_display_timings);251