cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

of_display_timing.c (6881B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * OF helpers for parsing display timings
      4 *
      5 * Copyright (c) 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>, Pengutronix
      6 *
      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_node
     17 * @np: device_node with the property
     18 * @name: name of the property
     19 * @result: will be set to the return value
     20 *
     21 * DESCRIPTION:
     22 * Every display_timing can be specified with either just the typical value or
     23 * a range consisting of min/typ/max. This function helps handling this
     24 **/
     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_node
     54 * @np: device_node with the properties
     55 * @dt: display_timing that contains the result. I may be partially written in case of errors
     56 **/
     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 entry
    115 * @np: device_node with the timing subnode
    116 * @name: name of the timing node
    117 * @dt: display_timing struct to fill
    118 **/
    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_node
    142 * @np: device_node with the subnodes
    143 **/
    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 of
    213			 * an error
    214			 */
    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_phandle
    230	 * therefore call of_node_put on it
    231	 */
    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);