1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | |
3 | #include <linux/clk.h> |
4 | #include <linux/of_clk.h> |
5 | #include <linux/minmax.h> |
6 | #include <linux/of_address.h> |
7 | #include <linux/platform_data/simplefb.h> |
8 | #include <linux/platform_device.h> |
9 | #include <linux/pm_domain.h> |
10 | #include <linux/regulator/consumer.h> |
11 | |
12 | #include <drm/drm_aperture.h> |
13 | #include <drm/drm_atomic.h> |
14 | #include <drm/drm_atomic_state_helper.h> |
15 | #include <drm/drm_connector.h> |
16 | #include <drm/drm_crtc_helper.h> |
17 | #include <drm/drm_damage_helper.h> |
18 | #include <drm/drm_device.h> |
19 | #include <drm/drm_drv.h> |
20 | #include <drm/drm_fbdev_generic.h> |
21 | #include <drm/drm_format_helper.h> |
22 | #include <drm/drm_gem_atomic_helper.h> |
23 | #include <drm/drm_gem_framebuffer_helper.h> |
24 | #include <drm/drm_gem_shmem_helper.h> |
25 | #include <drm/drm_managed.h> |
26 | #include <drm/drm_modeset_helper_vtables.h> |
27 | #include <drm/drm_plane_helper.h> |
28 | #include <drm/drm_probe_helper.h> |
29 | |
30 | #define DRIVER_NAME "simpledrm" |
31 | #define DRIVER_DESC "DRM driver for simple-framebuffer platform devices" |
32 | #define DRIVER_DATE "20200625" |
33 | #define DRIVER_MAJOR 1 |
34 | #define DRIVER_MINOR 0 |
35 | |
36 | /* |
37 | * Helpers for simplefb |
38 | */ |
39 | |
40 | static int |
41 | simplefb_get_validated_int(struct drm_device *dev, const char *name, |
42 | uint32_t value) |
43 | { |
44 | if (value > INT_MAX) { |
45 | drm_err(dev, "simplefb: invalid framebuffer %s of %u\n" , |
46 | name, value); |
47 | return -EINVAL; |
48 | } |
49 | return (int)value; |
50 | } |
51 | |
52 | static int |
53 | simplefb_get_validated_int0(struct drm_device *dev, const char *name, |
54 | uint32_t value) |
55 | { |
56 | if (!value) { |
57 | drm_err(dev, "simplefb: invalid framebuffer %s of %u\n" , |
58 | name, value); |
59 | return -EINVAL; |
60 | } |
61 | return simplefb_get_validated_int(dev, name, value); |
62 | } |
63 | |
64 | static const struct drm_format_info * |
65 | simplefb_get_validated_format(struct drm_device *dev, const char *format_name) |
66 | { |
67 | static const struct simplefb_format formats[] = SIMPLEFB_FORMATS; |
68 | const struct simplefb_format *fmt = formats; |
69 | const struct simplefb_format *end = fmt + ARRAY_SIZE(formats); |
70 | const struct drm_format_info *info; |
71 | |
72 | if (!format_name) { |
73 | drm_err(dev, "simplefb: missing framebuffer format\n" ); |
74 | return ERR_PTR(error: -EINVAL); |
75 | } |
76 | |
77 | while (fmt < end) { |
78 | if (!strcmp(format_name, fmt->name)) { |
79 | info = drm_format_info(format: fmt->fourcc); |
80 | if (!info) |
81 | return ERR_PTR(error: -EINVAL); |
82 | return info; |
83 | } |
84 | ++fmt; |
85 | } |
86 | |
87 | drm_err(dev, "simplefb: unknown framebuffer format %s\n" , |
88 | format_name); |
89 | |
90 | return ERR_PTR(error: -EINVAL); |
91 | } |
92 | |
93 | static int |
94 | simplefb_get_width_pd(struct drm_device *dev, |
95 | const struct simplefb_platform_data *pd) |
96 | { |
97 | return simplefb_get_validated_int0(dev, name: "width" , value: pd->width); |
98 | } |
99 | |
100 | static int |
101 | simplefb_get_height_pd(struct drm_device *dev, |
102 | const struct simplefb_platform_data *pd) |
103 | { |
104 | return simplefb_get_validated_int0(dev, name: "height" , value: pd->height); |
105 | } |
106 | |
107 | static int |
108 | simplefb_get_stride_pd(struct drm_device *dev, |
109 | const struct simplefb_platform_data *pd) |
110 | { |
111 | return simplefb_get_validated_int(dev, name: "stride" , value: pd->stride); |
112 | } |
113 | |
114 | static const struct drm_format_info * |
115 | simplefb_get_format_pd(struct drm_device *dev, |
116 | const struct simplefb_platform_data *pd) |
117 | { |
118 | return simplefb_get_validated_format(dev, format_name: pd->format); |
119 | } |
120 | |
121 | static int |
122 | simplefb_read_u32_of(struct drm_device *dev, struct device_node *of_node, |
123 | const char *name, u32 *value) |
124 | { |
125 | int ret = of_property_read_u32(np: of_node, propname: name, out_value: value); |
126 | |
127 | if (ret) |
128 | drm_err(dev, "simplefb: cannot parse framebuffer %s: error %d\n" , |
129 | name, ret); |
130 | return ret; |
131 | } |
132 | |
133 | static int |
134 | simplefb_read_string_of(struct drm_device *dev, struct device_node *of_node, |
135 | const char *name, const char **value) |
136 | { |
137 | int ret = of_property_read_string(np: of_node, propname: name, out_string: value); |
138 | |
139 | if (ret) |
140 | drm_err(dev, "simplefb: cannot parse framebuffer %s: error %d\n" , |
141 | name, ret); |
142 | return ret; |
143 | } |
144 | |
145 | static int |
146 | simplefb_get_width_of(struct drm_device *dev, struct device_node *of_node) |
147 | { |
148 | u32 width; |
149 | int ret = simplefb_read_u32_of(dev, of_node, name: "width" , value: &width); |
150 | |
151 | if (ret) |
152 | return ret; |
153 | return simplefb_get_validated_int0(dev, name: "width" , value: width); |
154 | } |
155 | |
156 | static int |
157 | simplefb_get_height_of(struct drm_device *dev, struct device_node *of_node) |
158 | { |
159 | u32 height; |
160 | int ret = simplefb_read_u32_of(dev, of_node, name: "height" , value: &height); |
161 | |
162 | if (ret) |
163 | return ret; |
164 | return simplefb_get_validated_int0(dev, name: "height" , value: height); |
165 | } |
166 | |
167 | static int |
168 | simplefb_get_stride_of(struct drm_device *dev, struct device_node *of_node) |
169 | { |
170 | u32 stride; |
171 | int ret = simplefb_read_u32_of(dev, of_node, name: "stride" , value: &stride); |
172 | |
173 | if (ret) |
174 | return ret; |
175 | return simplefb_get_validated_int(dev, name: "stride" , value: stride); |
176 | } |
177 | |
178 | static const struct drm_format_info * |
179 | simplefb_get_format_of(struct drm_device *dev, struct device_node *of_node) |
180 | { |
181 | const char *format; |
182 | int ret = simplefb_read_string_of(dev, of_node, name: "format" , value: &format); |
183 | |
184 | if (ret) |
185 | return ERR_PTR(error: ret); |
186 | return simplefb_get_validated_format(dev, format_name: format); |
187 | } |
188 | |
189 | static struct resource * |
190 | simplefb_get_memory_of(struct drm_device *dev, struct device_node *of_node) |
191 | { |
192 | struct device_node *np; |
193 | struct resource *res; |
194 | int err; |
195 | |
196 | np = of_parse_phandle(np: of_node, phandle_name: "memory-region" , index: 0); |
197 | if (!np) |
198 | return NULL; |
199 | |
200 | res = devm_kzalloc(dev: dev->dev, size: sizeof(*res), GFP_KERNEL); |
201 | if (!res) |
202 | return ERR_PTR(error: -ENOMEM); |
203 | |
204 | err = of_address_to_resource(dev: np, index: 0, r: res); |
205 | if (err) |
206 | return ERR_PTR(error: err); |
207 | |
208 | if (of_property_present(np: of_node, propname: "reg" )) |
209 | drm_warn(dev, "preferring \"memory-region\" over \"reg\" property\n" ); |
210 | |
211 | return res; |
212 | } |
213 | |
214 | /* |
215 | * Simple Framebuffer device |
216 | */ |
217 | |
218 | struct simpledrm_device { |
219 | struct drm_device dev; |
220 | |
221 | /* clocks */ |
222 | #if defined CONFIG_OF && defined CONFIG_COMMON_CLK |
223 | unsigned int clk_count; |
224 | struct clk **clks; |
225 | #endif |
226 | /* regulators */ |
227 | #if defined CONFIG_OF && defined CONFIG_REGULATOR |
228 | unsigned int regulator_count; |
229 | struct regulator **regulators; |
230 | #endif |
231 | /* power-domains */ |
232 | #if defined CONFIG_OF && defined CONFIG_PM_GENERIC_DOMAINS |
233 | int pwr_dom_count; |
234 | struct device **pwr_dom_devs; |
235 | struct device_link **pwr_dom_links; |
236 | #endif |
237 | |
238 | /* simplefb settings */ |
239 | struct drm_display_mode mode; |
240 | const struct drm_format_info *format; |
241 | unsigned int pitch; |
242 | |
243 | /* memory management */ |
244 | struct iosys_map screen_base; |
245 | |
246 | /* modesetting */ |
247 | uint32_t formats[8]; |
248 | size_t nformats; |
249 | struct drm_plane primary_plane; |
250 | struct drm_crtc crtc; |
251 | struct drm_encoder encoder; |
252 | struct drm_connector connector; |
253 | }; |
254 | |
255 | static struct simpledrm_device *simpledrm_device_of_dev(struct drm_device *dev) |
256 | { |
257 | return container_of(dev, struct simpledrm_device, dev); |
258 | } |
259 | |
260 | /* |
261 | * Hardware |
262 | */ |
263 | |
264 | #if defined CONFIG_OF && defined CONFIG_COMMON_CLK |
265 | /* |
266 | * Clock handling code. |
267 | * |
268 | * Here we handle the clocks property of our "simple-framebuffer" dt node. |
269 | * This is necessary so that we can make sure that any clocks needed by |
270 | * the display engine that the bootloader set up for us (and for which it |
271 | * provided a simplefb dt node), stay up, for the life of the simplefb |
272 | * driver. |
273 | * |
274 | * When the driver unloads, we cleanly disable, and then release the clocks. |
275 | * |
276 | * We only complain about errors here, no action is taken as the most likely |
277 | * error can only happen due to a mismatch between the bootloader which set |
278 | * up simplefb, and the clock definitions in the device tree. Chances are |
279 | * that there are no adverse effects, and if there are, a clean teardown of |
280 | * the fb probe will not help us much either. So just complain and carry on, |
281 | * and hope that the user actually gets a working fb at the end of things. |
282 | */ |
283 | |
284 | static void simpledrm_device_release_clocks(void *res) |
285 | { |
286 | struct simpledrm_device *sdev = simpledrm_device_of_dev(dev: res); |
287 | unsigned int i; |
288 | |
289 | for (i = 0; i < sdev->clk_count; ++i) { |
290 | if (sdev->clks[i]) { |
291 | clk_disable_unprepare(clk: sdev->clks[i]); |
292 | clk_put(clk: sdev->clks[i]); |
293 | } |
294 | } |
295 | } |
296 | |
297 | static int simpledrm_device_init_clocks(struct simpledrm_device *sdev) |
298 | { |
299 | struct drm_device *dev = &sdev->dev; |
300 | struct platform_device *pdev = to_platform_device(dev->dev); |
301 | struct device_node *of_node = pdev->dev.of_node; |
302 | struct clk *clock; |
303 | unsigned int i; |
304 | int ret; |
305 | |
306 | if (dev_get_platdata(dev: &pdev->dev) || !of_node) |
307 | return 0; |
308 | |
309 | sdev->clk_count = of_clk_get_parent_count(np: of_node); |
310 | if (!sdev->clk_count) |
311 | return 0; |
312 | |
313 | sdev->clks = drmm_kzalloc(dev, size: sdev->clk_count * sizeof(sdev->clks[0]), |
314 | GFP_KERNEL); |
315 | if (!sdev->clks) |
316 | return -ENOMEM; |
317 | |
318 | for (i = 0; i < sdev->clk_count; ++i) { |
319 | clock = of_clk_get(np: of_node, index: i); |
320 | if (IS_ERR(ptr: clock)) { |
321 | ret = PTR_ERR(ptr: clock); |
322 | if (ret == -EPROBE_DEFER) |
323 | goto err; |
324 | drm_err(dev, "clock %u not found: %d\n" , i, ret); |
325 | continue; |
326 | } |
327 | ret = clk_prepare_enable(clk: clock); |
328 | if (ret) { |
329 | drm_err(dev, "failed to enable clock %u: %d\n" , |
330 | i, ret); |
331 | clk_put(clk: clock); |
332 | continue; |
333 | } |
334 | sdev->clks[i] = clock; |
335 | } |
336 | |
337 | return devm_add_action_or_reset(&pdev->dev, |
338 | simpledrm_device_release_clocks, |
339 | sdev); |
340 | |
341 | err: |
342 | while (i) { |
343 | --i; |
344 | if (sdev->clks[i]) { |
345 | clk_disable_unprepare(clk: sdev->clks[i]); |
346 | clk_put(clk: sdev->clks[i]); |
347 | } |
348 | } |
349 | return ret; |
350 | } |
351 | #else |
352 | static int simpledrm_device_init_clocks(struct simpledrm_device *sdev) |
353 | { |
354 | return 0; |
355 | } |
356 | #endif |
357 | |
358 | #if defined CONFIG_OF && defined CONFIG_REGULATOR |
359 | |
360 | #define SUPPLY_SUFFIX "-supply" |
361 | |
362 | /* |
363 | * Regulator handling code. |
364 | * |
365 | * Here we handle the num-supplies and vin*-supply properties of our |
366 | * "simple-framebuffer" dt node. This is necessary so that we can make sure |
367 | * that any regulators needed by the display hardware that the bootloader |
368 | * set up for us (and for which it provided a simplefb dt node), stay up, |
369 | * for the life of the simplefb driver. |
370 | * |
371 | * When the driver unloads, we cleanly disable, and then release the |
372 | * regulators. |
373 | * |
374 | * We only complain about errors here, no action is taken as the most likely |
375 | * error can only happen due to a mismatch between the bootloader which set |
376 | * up simplefb, and the regulator definitions in the device tree. Chances are |
377 | * that there are no adverse effects, and if there are, a clean teardown of |
378 | * the fb probe will not help us much either. So just complain and carry on, |
379 | * and hope that the user actually gets a working fb at the end of things. |
380 | */ |
381 | |
382 | static void simpledrm_device_release_regulators(void *res) |
383 | { |
384 | struct simpledrm_device *sdev = simpledrm_device_of_dev(dev: res); |
385 | unsigned int i; |
386 | |
387 | for (i = 0; i < sdev->regulator_count; ++i) { |
388 | if (sdev->regulators[i]) { |
389 | regulator_disable(regulator: sdev->regulators[i]); |
390 | regulator_put(regulator: sdev->regulators[i]); |
391 | } |
392 | } |
393 | } |
394 | |
395 | static int simpledrm_device_init_regulators(struct simpledrm_device *sdev) |
396 | { |
397 | struct drm_device *dev = &sdev->dev; |
398 | struct platform_device *pdev = to_platform_device(dev->dev); |
399 | struct device_node *of_node = pdev->dev.of_node; |
400 | struct property *prop; |
401 | struct regulator *regulator; |
402 | const char *p; |
403 | unsigned int count = 0, i = 0; |
404 | int ret; |
405 | |
406 | if (dev_get_platdata(dev: &pdev->dev) || !of_node) |
407 | return 0; |
408 | |
409 | /* Count the number of regulator supplies */ |
410 | for_each_property_of_node(of_node, prop) { |
411 | p = strstr(prop->name, SUPPLY_SUFFIX); |
412 | if (p && p != prop->name) |
413 | ++count; |
414 | } |
415 | |
416 | if (!count) |
417 | return 0; |
418 | |
419 | sdev->regulators = drmm_kzalloc(dev, |
420 | size: count * sizeof(sdev->regulators[0]), |
421 | GFP_KERNEL); |
422 | if (!sdev->regulators) |
423 | return -ENOMEM; |
424 | |
425 | for_each_property_of_node(of_node, prop) { |
426 | char name[32]; /* 32 is max size of property name */ |
427 | size_t len; |
428 | |
429 | p = strstr(prop->name, SUPPLY_SUFFIX); |
430 | if (!p || p == prop->name) |
431 | continue; |
432 | len = strlen(prop->name) - strlen(SUPPLY_SUFFIX) + 1; |
433 | strscpy(p: name, q: prop->name, min(sizeof(name), len)); |
434 | |
435 | regulator = regulator_get_optional(dev: &pdev->dev, id: name); |
436 | if (IS_ERR(ptr: regulator)) { |
437 | ret = PTR_ERR(ptr: regulator); |
438 | if (ret == -EPROBE_DEFER) |
439 | goto err; |
440 | drm_err(dev, "regulator %s not found: %d\n" , |
441 | name, ret); |
442 | continue; |
443 | } |
444 | |
445 | ret = regulator_enable(regulator); |
446 | if (ret) { |
447 | drm_err(dev, "failed to enable regulator %u: %d\n" , |
448 | i, ret); |
449 | regulator_put(regulator); |
450 | continue; |
451 | } |
452 | |
453 | sdev->regulators[i++] = regulator; |
454 | } |
455 | sdev->regulator_count = i; |
456 | |
457 | return devm_add_action_or_reset(&pdev->dev, |
458 | simpledrm_device_release_regulators, |
459 | sdev); |
460 | |
461 | err: |
462 | while (i) { |
463 | --i; |
464 | if (sdev->regulators[i]) { |
465 | regulator_disable(regulator: sdev->regulators[i]); |
466 | regulator_put(regulator: sdev->regulators[i]); |
467 | } |
468 | } |
469 | return ret; |
470 | } |
471 | #else |
472 | static int simpledrm_device_init_regulators(struct simpledrm_device *sdev) |
473 | { |
474 | return 0; |
475 | } |
476 | #endif |
477 | |
478 | #if defined CONFIG_OF && defined CONFIG_PM_GENERIC_DOMAINS |
479 | /* |
480 | * Generic power domain handling code. |
481 | * |
482 | * Here we handle the power-domains properties of our "simple-framebuffer" |
483 | * dt node. This is only necessary if there is more than one power-domain. |
484 | * A single power-domains is handled automatically by the driver core. Multiple |
485 | * power-domains have to be handled by drivers since the driver core can't know |
486 | * the correct power sequencing. Power sequencing is not an issue for simpledrm |
487 | * since the bootloader has put the power domains already in the correct state. |
488 | * simpledrm has only to ensure they remain active for its lifetime. |
489 | * |
490 | * When the driver unloads, we detach from the power-domains. |
491 | * |
492 | * We only complain about errors here, no action is taken as the most likely |
493 | * error can only happen due to a mismatch between the bootloader which set |
494 | * up the "simple-framebuffer" dt node, and the PM domain providers in the |
495 | * device tree. Chances are that there are no adverse effects, and if there are, |
496 | * a clean teardown of the fb probe will not help us much either. So just |
497 | * complain and carry on, and hope that the user actually gets a working fb at |
498 | * the end of things. |
499 | */ |
500 | static void simpledrm_device_detach_genpd(void *res) |
501 | { |
502 | int i; |
503 | struct simpledrm_device *sdev = res; |
504 | |
505 | if (sdev->pwr_dom_count <= 1) |
506 | return; |
507 | |
508 | for (i = sdev->pwr_dom_count - 1; i >= 0; i--) { |
509 | if (sdev->pwr_dom_links[i]) |
510 | device_link_del(link: sdev->pwr_dom_links[i]); |
511 | if (!IS_ERR_OR_NULL(ptr: sdev->pwr_dom_devs[i])) |
512 | dev_pm_domain_detach(dev: sdev->pwr_dom_devs[i], power_off: true); |
513 | } |
514 | } |
515 | |
516 | static int simpledrm_device_attach_genpd(struct simpledrm_device *sdev) |
517 | { |
518 | struct device *dev = sdev->dev.dev; |
519 | int i; |
520 | |
521 | sdev->pwr_dom_count = of_count_phandle_with_args(np: dev->of_node, list_name: "power-domains" , |
522 | cells_name: "#power-domain-cells" ); |
523 | /* |
524 | * Single power-domain devices are handled by driver core nothing to do |
525 | * here. The same for device nodes without "power-domains" property. |
526 | */ |
527 | if (sdev->pwr_dom_count <= 1) |
528 | return 0; |
529 | |
530 | sdev->pwr_dom_devs = devm_kcalloc(dev, n: sdev->pwr_dom_count, |
531 | size: sizeof(*sdev->pwr_dom_devs), |
532 | GFP_KERNEL); |
533 | if (!sdev->pwr_dom_devs) |
534 | return -ENOMEM; |
535 | |
536 | sdev->pwr_dom_links = devm_kcalloc(dev, n: sdev->pwr_dom_count, |
537 | size: sizeof(*sdev->pwr_dom_links), |
538 | GFP_KERNEL); |
539 | if (!sdev->pwr_dom_links) |
540 | return -ENOMEM; |
541 | |
542 | for (i = 0; i < sdev->pwr_dom_count; i++) { |
543 | sdev->pwr_dom_devs[i] = dev_pm_domain_attach_by_id(dev, index: i); |
544 | if (IS_ERR(ptr: sdev->pwr_dom_devs[i])) { |
545 | int ret = PTR_ERR(ptr: sdev->pwr_dom_devs[i]); |
546 | if (ret == -EPROBE_DEFER) { |
547 | simpledrm_device_detach_genpd(res: sdev); |
548 | return ret; |
549 | } |
550 | drm_warn(&sdev->dev, |
551 | "pm_domain_attach_by_id(%u) failed: %d\n" , i, ret); |
552 | continue; |
553 | } |
554 | |
555 | sdev->pwr_dom_links[i] = device_link_add(consumer: dev, |
556 | supplier: sdev->pwr_dom_devs[i], |
557 | DL_FLAG_STATELESS | |
558 | DL_FLAG_PM_RUNTIME | |
559 | DL_FLAG_RPM_ACTIVE); |
560 | if (!sdev->pwr_dom_links[i]) |
561 | drm_warn(&sdev->dev, "failed to link power-domain %d\n" , i); |
562 | } |
563 | |
564 | return devm_add_action_or_reset(dev, simpledrm_device_detach_genpd, sdev); |
565 | } |
566 | #else |
567 | static int simpledrm_device_attach_genpd(struct simpledrm_device *sdev) |
568 | { |
569 | return 0; |
570 | } |
571 | #endif |
572 | |
573 | /* |
574 | * Modesetting |
575 | */ |
576 | |
577 | static const uint64_t simpledrm_primary_plane_format_modifiers[] = { |
578 | DRM_FORMAT_MOD_LINEAR, |
579 | DRM_FORMAT_MOD_INVALID |
580 | }; |
581 | |
582 | static void simpledrm_primary_plane_helper_atomic_update(struct drm_plane *plane, |
583 | struct drm_atomic_state *state) |
584 | { |
585 | struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); |
586 | struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); |
587 | struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state: plane_state); |
588 | struct drm_framebuffer *fb = plane_state->fb; |
589 | struct drm_device *dev = plane->dev; |
590 | struct simpledrm_device *sdev = simpledrm_device_of_dev(dev); |
591 | struct drm_atomic_helper_damage_iter iter; |
592 | struct drm_rect damage; |
593 | int ret, idx; |
594 | |
595 | ret = drm_gem_fb_begin_cpu_access(fb, dir: DMA_FROM_DEVICE); |
596 | if (ret) |
597 | return; |
598 | |
599 | if (!drm_dev_enter(dev, idx: &idx)) |
600 | goto out_drm_gem_fb_end_cpu_access; |
601 | |
602 | drm_atomic_helper_damage_iter_init(iter: &iter, old_state: old_plane_state, new_state: plane_state); |
603 | drm_atomic_for_each_plane_damage(&iter, &damage) { |
604 | struct drm_rect dst_clip = plane_state->dst; |
605 | struct iosys_map dst = sdev->screen_base; |
606 | |
607 | if (!drm_rect_intersect(r: &dst_clip, clip: &damage)) |
608 | continue; |
609 | |
610 | iosys_map_incr(map: &dst, incr: drm_fb_clip_offset(pitch: sdev->pitch, format: sdev->format, clip: &dst_clip)); |
611 | drm_fb_blit(dst: &dst, dst_pitch: &sdev->pitch, dst_format: sdev->format->format, src: shadow_plane_state->data, |
612 | fb, rect: &damage); |
613 | } |
614 | |
615 | drm_dev_exit(idx); |
616 | out_drm_gem_fb_end_cpu_access: |
617 | drm_gem_fb_end_cpu_access(fb, dir: DMA_FROM_DEVICE); |
618 | } |
619 | |
620 | static void simpledrm_primary_plane_helper_atomic_disable(struct drm_plane *plane, |
621 | struct drm_atomic_state *state) |
622 | { |
623 | struct drm_device *dev = plane->dev; |
624 | struct simpledrm_device *sdev = simpledrm_device_of_dev(dev); |
625 | int idx; |
626 | |
627 | if (!drm_dev_enter(dev, idx: &idx)) |
628 | return; |
629 | |
630 | /* Clear screen to black if disabled */ |
631 | iosys_map_memset(dst: &sdev->screen_base, offset: 0, value: 0, len: sdev->pitch * sdev->mode.vdisplay); |
632 | |
633 | drm_dev_exit(idx); |
634 | } |
635 | |
636 | static const struct drm_plane_helper_funcs simpledrm_primary_plane_helper_funcs = { |
637 | DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, |
638 | .atomic_check = drm_plane_helper_atomic_check, |
639 | .atomic_update = simpledrm_primary_plane_helper_atomic_update, |
640 | .atomic_disable = simpledrm_primary_plane_helper_atomic_disable, |
641 | }; |
642 | |
643 | static const struct drm_plane_funcs simpledrm_primary_plane_funcs = { |
644 | .update_plane = drm_atomic_helper_update_plane, |
645 | .disable_plane = drm_atomic_helper_disable_plane, |
646 | .destroy = drm_plane_cleanup, |
647 | DRM_GEM_SHADOW_PLANE_FUNCS, |
648 | }; |
649 | |
650 | static enum drm_mode_status simpledrm_crtc_helper_mode_valid(struct drm_crtc *crtc, |
651 | const struct drm_display_mode *mode) |
652 | { |
653 | struct simpledrm_device *sdev = simpledrm_device_of_dev(dev: crtc->dev); |
654 | |
655 | return drm_crtc_helper_mode_valid_fixed(crtc, mode, fixed_mode: &sdev->mode); |
656 | } |
657 | |
658 | /* |
659 | * The CRTC is always enabled. Screen updates are performed by |
660 | * the primary plane's atomic_update function. Disabling clears |
661 | * the screen in the primary plane's atomic_disable function. |
662 | */ |
663 | static const struct drm_crtc_helper_funcs simpledrm_crtc_helper_funcs = { |
664 | .mode_valid = simpledrm_crtc_helper_mode_valid, |
665 | .atomic_check = drm_crtc_helper_atomic_check, |
666 | }; |
667 | |
668 | static const struct drm_crtc_funcs simpledrm_crtc_funcs = { |
669 | .reset = drm_atomic_helper_crtc_reset, |
670 | .destroy = drm_crtc_cleanup, |
671 | .set_config = drm_atomic_helper_set_config, |
672 | .page_flip = drm_atomic_helper_page_flip, |
673 | .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, |
674 | .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, |
675 | }; |
676 | |
677 | static const struct drm_encoder_funcs simpledrm_encoder_funcs = { |
678 | .destroy = drm_encoder_cleanup, |
679 | }; |
680 | |
681 | static int simpledrm_connector_helper_get_modes(struct drm_connector *connector) |
682 | { |
683 | struct simpledrm_device *sdev = simpledrm_device_of_dev(dev: connector->dev); |
684 | |
685 | return drm_connector_helper_get_modes_fixed(connector, fixed_mode: &sdev->mode); |
686 | } |
687 | |
688 | static const struct drm_connector_helper_funcs simpledrm_connector_helper_funcs = { |
689 | .get_modes = simpledrm_connector_helper_get_modes, |
690 | }; |
691 | |
692 | static const struct drm_connector_funcs simpledrm_connector_funcs = { |
693 | .reset = drm_atomic_helper_connector_reset, |
694 | .fill_modes = drm_helper_probe_single_connector_modes, |
695 | .destroy = drm_connector_cleanup, |
696 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
697 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
698 | }; |
699 | |
700 | static const struct drm_mode_config_funcs simpledrm_mode_config_funcs = { |
701 | .fb_create = drm_gem_fb_create_with_dirty, |
702 | .atomic_check = drm_atomic_helper_check, |
703 | .atomic_commit = drm_atomic_helper_commit, |
704 | }; |
705 | |
706 | /* |
707 | * Init / Cleanup |
708 | */ |
709 | |
710 | static struct drm_display_mode simpledrm_mode(unsigned int width, |
711 | unsigned int height, |
712 | unsigned int width_mm, |
713 | unsigned int height_mm) |
714 | { |
715 | const struct drm_display_mode mode = { |
716 | DRM_MODE_INIT(60, width, height, width_mm, height_mm) |
717 | }; |
718 | |
719 | return mode; |
720 | } |
721 | |
722 | static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv, |
723 | struct platform_device *pdev) |
724 | { |
725 | const struct simplefb_platform_data *pd = dev_get_platdata(dev: &pdev->dev); |
726 | struct device_node *of_node = pdev->dev.of_node; |
727 | struct simpledrm_device *sdev; |
728 | struct drm_device *dev; |
729 | int width, height, stride; |
730 | int width_mm = 0, height_mm = 0; |
731 | struct device_node *panel_node; |
732 | const struct drm_format_info *format; |
733 | struct resource *res, *mem = NULL; |
734 | struct drm_plane *primary_plane; |
735 | struct drm_crtc *crtc; |
736 | struct drm_encoder *encoder; |
737 | struct drm_connector *connector; |
738 | unsigned long max_width, max_height; |
739 | size_t nformats; |
740 | int ret; |
741 | |
742 | sdev = devm_drm_dev_alloc(&pdev->dev, drv, struct simpledrm_device, dev); |
743 | if (IS_ERR(ptr: sdev)) |
744 | return ERR_CAST(ptr: sdev); |
745 | dev = &sdev->dev; |
746 | platform_set_drvdata(pdev, data: sdev); |
747 | |
748 | /* |
749 | * Hardware settings |
750 | */ |
751 | |
752 | ret = simpledrm_device_init_clocks(sdev); |
753 | if (ret) |
754 | return ERR_PTR(error: ret); |
755 | ret = simpledrm_device_init_regulators(sdev); |
756 | if (ret) |
757 | return ERR_PTR(error: ret); |
758 | ret = simpledrm_device_attach_genpd(sdev); |
759 | if (ret) |
760 | return ERR_PTR(error: ret); |
761 | |
762 | if (pd) { |
763 | width = simplefb_get_width_pd(dev, pd); |
764 | if (width < 0) |
765 | return ERR_PTR(error: width); |
766 | height = simplefb_get_height_pd(dev, pd); |
767 | if (height < 0) |
768 | return ERR_PTR(error: height); |
769 | stride = simplefb_get_stride_pd(dev, pd); |
770 | if (stride < 0) |
771 | return ERR_PTR(error: stride); |
772 | format = simplefb_get_format_pd(dev, pd); |
773 | if (IS_ERR(ptr: format)) |
774 | return ERR_CAST(ptr: format); |
775 | } else if (of_node) { |
776 | width = simplefb_get_width_of(dev, of_node); |
777 | if (width < 0) |
778 | return ERR_PTR(error: width); |
779 | height = simplefb_get_height_of(dev, of_node); |
780 | if (height < 0) |
781 | return ERR_PTR(error: height); |
782 | stride = simplefb_get_stride_of(dev, of_node); |
783 | if (stride < 0) |
784 | return ERR_PTR(error: stride); |
785 | format = simplefb_get_format_of(dev, of_node); |
786 | if (IS_ERR(ptr: format)) |
787 | return ERR_CAST(ptr: format); |
788 | mem = simplefb_get_memory_of(dev, of_node); |
789 | if (IS_ERR(ptr: mem)) |
790 | return ERR_CAST(ptr: mem); |
791 | panel_node = of_parse_phandle(np: of_node, phandle_name: "panel" , index: 0); |
792 | if (panel_node) { |
793 | simplefb_read_u32_of(dev, of_node: panel_node, name: "width-mm" , value: &width_mm); |
794 | simplefb_read_u32_of(dev, of_node: panel_node, name: "height-mm" , value: &height_mm); |
795 | of_node_put(node: panel_node); |
796 | } |
797 | } else { |
798 | drm_err(dev, "no simplefb configuration found\n" ); |
799 | return ERR_PTR(error: -ENODEV); |
800 | } |
801 | if (!stride) { |
802 | stride = drm_format_info_min_pitch(info: format, plane: 0, buffer_width: width); |
803 | if (drm_WARN_ON(dev, !stride)) |
804 | return ERR_PTR(error: -EINVAL); |
805 | } |
806 | |
807 | /* |
808 | * Assume a monitor resolution of 96 dpi if physical dimensions |
809 | * are not specified to get a somewhat reasonable screen size. |
810 | */ |
811 | if (!width_mm) |
812 | width_mm = DRM_MODE_RES_MM(width, 96ul); |
813 | if (!height_mm) |
814 | height_mm = DRM_MODE_RES_MM(height, 96ul); |
815 | |
816 | sdev->mode = simpledrm_mode(width, height, width_mm, height_mm); |
817 | sdev->format = format; |
818 | sdev->pitch = stride; |
819 | |
820 | drm_dbg(dev, "display mode={" DRM_MODE_FMT "}\n" , DRM_MODE_ARG(&sdev->mode)); |
821 | drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, stride=%d byte\n" , |
822 | &format->format, width, height, stride); |
823 | |
824 | /* |
825 | * Memory management |
826 | */ |
827 | |
828 | if (mem) { |
829 | void *screen_base; |
830 | |
831 | ret = devm_aperture_acquire_from_firmware(dev, base: mem->start, size: resource_size(res: mem)); |
832 | if (ret) { |
833 | drm_err(dev, "could not acquire memory range %pr: %d\n" , mem, ret); |
834 | return ERR_PTR(error: ret); |
835 | } |
836 | |
837 | drm_dbg(dev, "using system memory framebuffer at %pr\n" , mem); |
838 | |
839 | screen_base = devm_memremap(dev: dev->dev, offset: mem->start, size: resource_size(res: mem), flags: MEMREMAP_WC); |
840 | if (IS_ERR(ptr: screen_base)) |
841 | return screen_base; |
842 | |
843 | iosys_map_set_vaddr(map: &sdev->screen_base, vaddr: screen_base); |
844 | } else { |
845 | void __iomem *screen_base; |
846 | |
847 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
848 | if (!res) |
849 | return ERR_PTR(error: -EINVAL); |
850 | |
851 | ret = devm_aperture_acquire_from_firmware(dev, base: res->start, size: resource_size(res)); |
852 | if (ret) { |
853 | drm_err(dev, "could not acquire memory range %pr: %d\n" , res, ret); |
854 | return ERR_PTR(error: ret); |
855 | } |
856 | |
857 | drm_dbg(dev, "using I/O memory framebuffer at %pr\n" , res); |
858 | |
859 | mem = devm_request_mem_region(&pdev->dev, res->start, resource_size(res), |
860 | drv->name); |
861 | if (!mem) { |
862 | /* |
863 | * We cannot make this fatal. Sometimes this comes from magic |
864 | * spaces our resource handlers simply don't know about. Use |
865 | * the I/O-memory resource as-is and try to map that instead. |
866 | */ |
867 | drm_warn(dev, "could not acquire memory region %pr\n" , res); |
868 | mem = res; |
869 | } |
870 | |
871 | screen_base = devm_ioremap_wc(dev: &pdev->dev, offset: mem->start, size: resource_size(res: mem)); |
872 | if (!screen_base) |
873 | return ERR_PTR(error: -ENOMEM); |
874 | |
875 | iosys_map_set_vaddr_iomem(map: &sdev->screen_base, vaddr_iomem: screen_base); |
876 | } |
877 | |
878 | /* |
879 | * Modesetting |
880 | */ |
881 | |
882 | ret = drmm_mode_config_init(dev); |
883 | if (ret) |
884 | return ERR_PTR(error: ret); |
885 | |
886 | max_width = max_t(unsigned long, width, DRM_SHADOW_PLANE_MAX_WIDTH); |
887 | max_height = max_t(unsigned long, height, DRM_SHADOW_PLANE_MAX_HEIGHT); |
888 | |
889 | dev->mode_config.min_width = width; |
890 | dev->mode_config.max_width = max_width; |
891 | dev->mode_config.min_height = height; |
892 | dev->mode_config.max_height = max_height; |
893 | dev->mode_config.preferred_depth = format->depth; |
894 | dev->mode_config.funcs = &simpledrm_mode_config_funcs; |
895 | |
896 | /* Primary plane */ |
897 | |
898 | nformats = drm_fb_build_fourcc_list(dev, native_fourccs: &format->format, native_nfourccs: 1, |
899 | fourccs_out: sdev->formats, ARRAY_SIZE(sdev->formats)); |
900 | |
901 | primary_plane = &sdev->primary_plane; |
902 | ret = drm_universal_plane_init(dev, plane: primary_plane, possible_crtcs: 0, funcs: &simpledrm_primary_plane_funcs, |
903 | formats: sdev->formats, format_count: nformats, |
904 | format_modifiers: simpledrm_primary_plane_format_modifiers, |
905 | type: DRM_PLANE_TYPE_PRIMARY, NULL); |
906 | if (ret) |
907 | return ERR_PTR(error: ret); |
908 | drm_plane_helper_add(plane: primary_plane, funcs: &simpledrm_primary_plane_helper_funcs); |
909 | drm_plane_enable_fb_damage_clips(plane: primary_plane); |
910 | |
911 | /* CRTC */ |
912 | |
913 | crtc = &sdev->crtc; |
914 | ret = drm_crtc_init_with_planes(dev, crtc, primary: primary_plane, NULL, |
915 | funcs: &simpledrm_crtc_funcs, NULL); |
916 | if (ret) |
917 | return ERR_PTR(error: ret); |
918 | drm_crtc_helper_add(crtc, funcs: &simpledrm_crtc_helper_funcs); |
919 | |
920 | /* Encoder */ |
921 | |
922 | encoder = &sdev->encoder; |
923 | ret = drm_encoder_init(dev, encoder, funcs: &simpledrm_encoder_funcs, |
924 | DRM_MODE_ENCODER_NONE, NULL); |
925 | if (ret) |
926 | return ERR_PTR(error: ret); |
927 | encoder->possible_crtcs = drm_crtc_mask(crtc); |
928 | |
929 | /* Connector */ |
930 | |
931 | connector = &sdev->connector; |
932 | ret = drm_connector_init(dev, connector, funcs: &simpledrm_connector_funcs, |
933 | DRM_MODE_CONNECTOR_Unknown); |
934 | if (ret) |
935 | return ERR_PTR(error: ret); |
936 | drm_connector_helper_add(connector, funcs: &simpledrm_connector_helper_funcs); |
937 | drm_connector_set_panel_orientation_with_quirk(connector, |
938 | panel_orientation: DRM_MODE_PANEL_ORIENTATION_UNKNOWN, |
939 | width, height); |
940 | |
941 | ret = drm_connector_attach_encoder(connector, encoder); |
942 | if (ret) |
943 | return ERR_PTR(error: ret); |
944 | |
945 | drm_mode_config_reset(dev); |
946 | |
947 | return sdev; |
948 | } |
949 | |
950 | /* |
951 | * DRM driver |
952 | */ |
953 | |
954 | DEFINE_DRM_GEM_FOPS(simpledrm_fops); |
955 | |
956 | static struct drm_driver simpledrm_driver = { |
957 | DRM_GEM_SHMEM_DRIVER_OPS, |
958 | .name = DRIVER_NAME, |
959 | .desc = DRIVER_DESC, |
960 | .date = DRIVER_DATE, |
961 | .major = DRIVER_MAJOR, |
962 | .minor = DRIVER_MINOR, |
963 | .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET, |
964 | .fops = &simpledrm_fops, |
965 | }; |
966 | |
967 | /* |
968 | * Platform driver |
969 | */ |
970 | |
971 | static int simpledrm_probe(struct platform_device *pdev) |
972 | { |
973 | struct simpledrm_device *sdev; |
974 | struct drm_device *dev; |
975 | unsigned int color_mode; |
976 | int ret; |
977 | |
978 | sdev = simpledrm_device_create(drv: &simpledrm_driver, pdev); |
979 | if (IS_ERR(ptr: sdev)) |
980 | return PTR_ERR(ptr: sdev); |
981 | dev = &sdev->dev; |
982 | |
983 | ret = drm_dev_register(dev, flags: 0); |
984 | if (ret) |
985 | return ret; |
986 | |
987 | color_mode = drm_format_info_bpp(info: sdev->format, plane: 0); |
988 | if (color_mode == 16) |
989 | color_mode = sdev->format->depth; // can be 15 or 16 |
990 | |
991 | drm_fbdev_generic_setup(dev, preferred_bpp: color_mode); |
992 | |
993 | return 0; |
994 | } |
995 | |
996 | static void simpledrm_remove(struct platform_device *pdev) |
997 | { |
998 | struct simpledrm_device *sdev = platform_get_drvdata(pdev); |
999 | struct drm_device *dev = &sdev->dev; |
1000 | |
1001 | drm_dev_unplug(dev); |
1002 | } |
1003 | |
1004 | static const struct of_device_id simpledrm_of_match_table[] = { |
1005 | { .compatible = "simple-framebuffer" , }, |
1006 | { }, |
1007 | }; |
1008 | MODULE_DEVICE_TABLE(of, simpledrm_of_match_table); |
1009 | |
1010 | static struct platform_driver simpledrm_platform_driver = { |
1011 | .driver = { |
1012 | .name = "simple-framebuffer" , /* connect to sysfb */ |
1013 | .of_match_table = simpledrm_of_match_table, |
1014 | }, |
1015 | .probe = simpledrm_probe, |
1016 | .remove_new = simpledrm_remove, |
1017 | }; |
1018 | |
1019 | module_platform_driver(simpledrm_platform_driver); |
1020 | |
1021 | MODULE_DESCRIPTION(DRIVER_DESC); |
1022 | MODULE_LICENSE("GPL v2" ); |
1023 | |