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