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