Coverage Report

Created: 2026-10-17 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/barebox/drivers/video/of_display_timing.c
Line
Count
Source
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 <common.h>
10
#include <of.h>
11
#include <fb.h>
12
#include <malloc.h>
13
14
void display_timings_release(struct display_timings *disp)
15
0
{
16
0
  if (disp->modes)
17
0
    free(disp->modes);
18
0
  free(disp);
19
0
}
20
EXPORT_SYMBOL_GPL(display_timings_release);
21
22
/**
23
 * parse_timing_property - parse timing_entry from device_node
24
 * @np: device_node with the property
25
 * @name: name of the property
26
 * @result: will be set to the return value
27
 *
28
 * DESCRIPTION:
29
 * Every display_timing can be specified with either just the typical value or
30
 * a range consisting of min/typ/max. This function helps handling this
31
 **/
32
static int parse_timing_property(const struct device_node *np, const char *name,
33
        u32 *res)
34
0
{
35
0
  struct property *prop;
36
0
  int length, cells, ret;
37
38
0
  prop = of_find_property(np, name, &length);
39
0
  if (!prop) {
40
0
    pr_err("%pOF: could not find property %s\n",
41
0
      np, name);
42
0
    return -EINVAL;
43
0
  }
44
45
0
  cells = length / sizeof(u32);
46
0
  if ((cells == 1) || (cells == 3)) {
47
0
    ret = of_property_read_u32(np, name, res);
48
0
  } else {
49
0
    pr_err("%pOF: illegal timing specification in %s\n",
50
0
      np, name);
51
0
    return -EINVAL;
52
0
  }
53
54
0
  return ret;
55
0
}
56
57
/**
58
 * of_parse_display_timing - parse display_timing entry from device_node
59
 * @np: device_node with the properties
60
 **/
61
static int of_parse_display_timing(const struct device_node *np,
62
    struct fb_videomode *mode)
63
0
{
64
0
  u32 val = 0, pixelclock = 0;
65
0
  int ret = 0;
66
67
0
  memset(mode, 0, sizeof(*mode));
68
69
0
  ret |= parse_timing_property(np, "hback-porch", &mode->left_margin);
70
0
  ret |= parse_timing_property(np, "hfront-porch", &mode->right_margin);
71
0
  ret |= parse_timing_property(np, "hactive", &mode->xres);
72
0
  ret |= parse_timing_property(np, "hsync-len", &mode->hsync_len);
73
0
  ret |= parse_timing_property(np, "vback-porch", &mode->upper_margin);
74
0
  ret |= parse_timing_property(np, "vfront-porch", &mode->lower_margin);
75
0
  ret |= parse_timing_property(np, "vactive", &mode->yres);
76
0
  ret |= parse_timing_property(np, "vsync-len", &mode->vsync_len);
77
0
  ret |= parse_timing_property(np, "clock-frequency", &pixelclock);
78
79
0
  fb_videomode_set_pixclock_hz(mode, pixelclock);
80
81
0
  if (!of_property_read_u32(np, "vsync-active", &val))
82
0
    mode->sync |= val ? FB_SYNC_VERT_HIGH_ACT : 0;
83
0
  if (!of_property_read_u32(np, "hsync-active", &val))
84
0
    mode->sync |= val ? FB_SYNC_HOR_HIGH_ACT : 0;
85
0
  if (!of_property_read_u32(np, "de-active", &val))
86
0
    mode->display_flags |= val ? DISPLAY_FLAGS_DE_HIGH :
87
0
        DISPLAY_FLAGS_DE_LOW;
88
0
  if (!of_property_read_u32(np, "pixelclk-active", &val))
89
0
    mode->display_flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
90
0
        DISPLAY_FLAGS_PIXDATA_NEGEDGE;
91
92
0
  if (ret) {
93
0
    pr_err("%pOF: error reading timing properties\n", np);
94
0
    return -EINVAL;
95
0
  }
96
97
0
  return 0;
98
0
}
99
100
/**
101
 * of_get_display_timing - parse a display_timing entry
102
 * @np: device_node with the timing subnode
103
 * @name: name of the timing node
104
 * @mode: fb_videomode struct to fill
105
 **/
106
int of_get_display_timing(const struct device_node *np, const char *name,
107
        struct fb_videomode *mode)
108
0
{
109
0
  struct device_node *timing_np;
110
111
0
  if (!np)
112
0
    return -EINVAL;
113
114
0
  timing_np = of_get_child_by_name(np, name);
115
0
  if (!timing_np)
116
0
    return -ENOENT;
117
118
0
  return of_parse_display_timing(timing_np, mode);
119
0
}
120
EXPORT_SYMBOL_GPL(of_get_display_timing);
121
122
/**
123
 * of_get_display_timings - parse all display_timing entries from a device_node
124
 * @np: device_node with the subnodes
125
 **/
126
struct display_timings *of_get_display_timings(struct device_node *np)
127
0
{
128
0
  struct device_node *timings_np;
129
0
  struct device_node *entry;
130
0
  struct device_node *native_mode;
131
0
  struct display_timings *disp;
132
133
0
  if (!np)
134
0
    return NULL;
135
136
0
  timings_np = of_get_child_by_name(np, "display-timings");
137
0
  if (!timings_np) {
138
0
    pr_debug("%pOF: could not find display-timings node\n", np);
139
0
    return NULL;
140
0
  }
141
142
0
  disp = xzalloc(sizeof(*disp));
143
144
0
  entry = of_parse_phandle(timings_np, "native-mode", 0);
145
  /* assume first child as native mode if none provided */
146
0
  if (!entry)
147
0
    entry = of_get_next_available_child(np, NULL);
148
  /* if there is no child, it is useless to go on */
149
0
  if (!entry) {
150
0
    pr_err("%pOF: no timing specifications given\n", np);
151
0
    goto fail;
152
0
  }
153
154
0
  pr_debug("%pOF: using %s as default timing\n",
155
0
    np, entry->name);
156
157
0
  native_mode = entry;
158
159
0
  disp->num_modes = of_get_child_count(timings_np);
160
0
  if (disp->num_modes == 0) {
161
    /* should never happen, as entry was already found above */
162
0
    pr_err("%pOF: no timings specified\n", np);
163
0
    goto fail;
164
0
  }
165
166
0
  disp->modes = xzalloc(sizeof(struct fb_videomode) * disp->num_modes);
167
168
0
  disp->num_modes = 0;
169
0
  disp->native_mode = 0;
170
171
0
  for_each_child_of_node(timings_np, entry) {
172
0
    struct fb_videomode *mode;
173
0
    int r;
174
175
0
    mode = &disp->modes[disp->num_modes];
176
177
0
    r = of_parse_display_timing(entry, mode);
178
0
    if (r) {
179
      /*
180
       * to not encourage wrong devicetrees, fail in case of
181
       * an error
182
       */
183
0
      pr_err("%pOF: error in timing %d\n",
184
0
        np, disp->num_modes + 1);
185
0
      goto fail;
186
0
    }
187
188
0
    mode->name = xstrdup(entry->name);
189
190
0
    if (native_mode == entry)
191
0
      disp->native_mode = disp->num_modes;
192
193
0
    disp->num_modes++;
194
0
  }
195
196
0
  pr_debug("%pOF: got %d timings. Using timing #%d as default\n",
197
0
    np, disp->num_modes,
198
0
    disp->native_mode + 1);
199
200
0
  return disp;
201
202
0
fail:
203
0
  display_timings_release(disp);
204
205
0
  return NULL;
206
0
}
207
EXPORT_SYMBOL_GPL(of_get_display_timings);