xref: /linux/drivers/gpu/drm/sysfb/vesadrm.c (revision a84eb6abe2b6a7201610645749275c8ac999fd1a)
1 // SPDX-License-Identifier: GPL-2.0-only
2 
3 #include <linux/aperture.h>
4 #include <linux/ioport.h>
5 #include <linux/limits.h>
6 #include <linux/platform_device.h>
7 #include <linux/screen_info.h>
8 
9 #include <drm/clients/drm_client_setup.h>
10 #include <drm/drm_atomic.h>
11 #include <drm/drm_atomic_state_helper.h>
12 #include <drm/drm_connector.h>
13 #include <drm/drm_damage_helper.h>
14 #include <drm/drm_device.h>
15 #include <drm/drm_drv.h>
16 #include <drm/drm_fbdev_shmem.h>
17 #include <drm/drm_framebuffer.h>
18 #include <drm/drm_gem_atomic_helper.h>
19 #include <drm/drm_gem_framebuffer_helper.h>
20 #include <drm/drm_gem_shmem_helper.h>
21 #include <drm/drm_managed.h>
22 #include <drm/drm_modeset_helper_vtables.h>
23 #include <drm/drm_probe_helper.h>
24 
25 #include <video/pixel_format.h>
26 
27 #include "drm_sysfb_helper.h"
28 
29 #define DRIVER_NAME	"vesadrm"
30 #define DRIVER_DESC	"DRM driver for VESA platform devices"
31 #define DRIVER_MAJOR	1
32 #define DRIVER_MINOR	0
33 
34 static int vesadrm_get_validated_int(struct drm_device *dev, const char *name,
35 				     u64 value, u32 max)
36 {
37 	if (max > INT_MAX)
38 		max = INT_MAX;
39 	if (value > max) {
40 		drm_err(dev, "%s of %llu exceeds maximum of %u\n", name, value, max);
41 		return -EINVAL;
42 	}
43 	return value;
44 }
45 
46 static int vesadrm_get_validated_int0(struct drm_device *dev, const char *name,
47 				      u64 value, u32 max)
48 {
49 	if (!value) {
50 		drm_err(dev, "%s of 0 not allowed\n", name);
51 		return -EINVAL;
52 	}
53 	return vesadrm_get_validated_int(dev, name, value, max);
54 }
55 
56 static s64 vesadrm_get_validated_size0(struct drm_device *dev, const char *name,
57 				       u64 value, u64 max)
58 {
59 	if (!value) {
60 		drm_err(dev, "vesadrm: %s of 0 not allowed\n", name);
61 		return -EINVAL;
62 	} else if (value > max) {
63 		drm_err(dev, "vesadrm: %s of %llu exceeds maximum of %llu\n", name, value, max);
64 		return -EINVAL;
65 	}
66 	return value;
67 }
68 
69 static int vesadrm_get_width_si(struct drm_device *dev, const struct screen_info *si)
70 {
71 	return vesadrm_get_validated_int0(dev, "width", si->lfb_width, U16_MAX);
72 }
73 
74 static int vesadrm_get_height_si(struct drm_device *dev, const struct screen_info *si)
75 {
76 	return vesadrm_get_validated_int0(dev, "height", si->lfb_height, U16_MAX);
77 }
78 
79 static struct resource *vesadrm_get_memory_si(struct drm_device *dev,
80 					      const struct screen_info *si,
81 					      struct resource *res)
82 {
83 	ssize_t	num;
84 
85 	num = screen_info_resources(si, res, 1);
86 	if (!num) {
87 		drm_err(dev, "vesadrm: memory resource not found\n");
88 		return NULL;
89 	}
90 
91 	return res;
92 }
93 
94 static int vesadrm_get_stride_si(struct drm_device *dev, const struct screen_info *si,
95 				 const struct drm_format_info *format,
96 				 unsigned int width, unsigned int height, u64 size)
97 {
98 	u64 lfb_linelength = si->lfb_linelength;
99 
100 	if (!lfb_linelength)
101 		lfb_linelength = drm_format_info_min_pitch(format, 0, width);
102 
103 	return vesadrm_get_validated_int0(dev, "stride", lfb_linelength, div64_u64(size, height));
104 }
105 
106 static u64 vesadrm_get_visible_size_si(struct drm_device *dev, const struct screen_info *si,
107 				       unsigned int height, unsigned int stride, u64 size)
108 {
109 	u64 vsize = PAGE_ALIGN(height * stride);
110 
111 	return vesadrm_get_validated_size0(dev, "visible size", vsize, size);
112 }
113 
114 static const struct drm_format_info *vesadrm_get_format_si(struct drm_device *dev,
115 							   const struct screen_info *si)
116 {
117 	static const struct {
118 		struct pixel_format pixel;
119 		u32 fourcc;
120 	} vesa_formats[] = {
121 		{ PIXEL_FORMAT_XRGB1555, DRM_FORMAT_XRGB1555, },
122 		{ PIXEL_FORMAT_RGB565, DRM_FORMAT_RGB565, },
123 		{ PIXEL_FORMAT_RGB888, DRM_FORMAT_RGB888, },
124 		{ PIXEL_FORMAT_XRGB8888, DRM_FORMAT_XRGB8888, },
125 		{ PIXEL_FORMAT_XBGR8888, DRM_FORMAT_XBGR8888, },
126 	};
127 	const struct drm_format_info *format = NULL;
128 	u32 bits_per_pixel;
129 	size_t i;
130 
131 	bits_per_pixel = __screen_info_lfb_bits_per_pixel(si);
132 
133 	for (i = 0; i < ARRAY_SIZE(vesa_formats); ++i) {
134 		const struct pixel_format *f = &vesa_formats[i].pixel;
135 
136 		if (bits_per_pixel == f->bits_per_pixel &&
137 		    si->red_size == f->red.length &&
138 		    si->red_pos == f->red.offset &&
139 		    si->green_size == f->green.length &&
140 		    si->green_pos == f->green.offset &&
141 		    si->blue_size == f->blue.length &&
142 		    si->blue_pos == f->blue.offset) {
143 			format = drm_format_info(vesa_formats[i].fourcc);
144 			break;
145 		}
146 	}
147 
148 	if (!format)
149 		return ERR_PTR(-EINVAL);
150 	if (format->is_color_indexed)
151 		return ERR_PTR(-EINVAL);
152 
153 	return format;
154 }
155 
156 /*
157  * VESA device
158  */
159 
160 struct vesadrm_device {
161 	struct drm_sysfb_device sysfb;
162 
163 	/* modesetting */
164 	u32 formats[DRM_SYSFB_PLANE_NFORMATS(1)];
165 	struct drm_plane primary_plane;
166 	struct drm_crtc crtc;
167 	struct drm_encoder encoder;
168 	struct drm_connector connector;
169 };
170 
171 /*
172  * Modesetting
173  */
174 
175 static const u64 vesadrm_primary_plane_format_modifiers[] = {
176 	DRM_SYSFB_PLANE_FORMAT_MODIFIERS,
177 };
178 
179 static const struct drm_plane_helper_funcs vesadrm_primary_plane_helper_funcs = {
180 	DRM_SYSFB_PLANE_HELPER_FUNCS,
181 };
182 
183 static const struct drm_plane_funcs vesadrm_primary_plane_funcs = {
184 	DRM_SYSFB_PLANE_FUNCS,
185 	.destroy = drm_plane_cleanup,
186 };
187 
188 static const struct drm_crtc_helper_funcs vesadrm_crtc_helper_funcs = {
189 	DRM_SYSFB_CRTC_HELPER_FUNCS,
190 };
191 
192 static const struct drm_crtc_funcs vesadrm_crtc_funcs = {
193 	DRM_SYSFB_CRTC_FUNCS,
194 	.destroy = drm_crtc_cleanup,
195 };
196 
197 static const struct drm_encoder_funcs vesadrm_encoder_funcs = {
198 	.destroy = drm_encoder_cleanup,
199 };
200 
201 static const struct drm_connector_helper_funcs vesadrm_connector_helper_funcs = {
202 	DRM_SYSFB_CONNECTOR_HELPER_FUNCS,
203 };
204 
205 static const struct drm_connector_funcs vesadrm_connector_funcs = {
206 	DRM_SYSFB_CONNECTOR_FUNCS,
207 	.destroy = drm_connector_cleanup,
208 };
209 
210 static const struct drm_mode_config_funcs vesadrm_mode_config_funcs = {
211 	DRM_SYSFB_MODE_CONFIG_FUNCS,
212 };
213 
214 /*
215  * Init / Cleanup
216  */
217 
218 static struct vesadrm_device *vesadrm_device_create(struct drm_driver *drv,
219 						    struct platform_device *pdev)
220 {
221 	const struct screen_info *si;
222 	const struct drm_format_info *format;
223 	int width, height, stride;
224 	u64 vsize;
225 	struct resource resbuf;
226 	struct resource *res;
227 	struct vesadrm_device *vesa;
228 	struct drm_sysfb_device *sysfb;
229 	struct drm_device *dev;
230 	struct resource *mem = NULL;
231 	void __iomem *screen_base;
232 	struct drm_plane *primary_plane;
233 	struct drm_crtc *crtc;
234 	struct drm_encoder *encoder;
235 	struct drm_connector *connector;
236 	unsigned long max_width, max_height;
237 	size_t nformats;
238 	int ret;
239 
240 	si = dev_get_platdata(&pdev->dev);
241 	if (!si)
242 		return ERR_PTR(-ENODEV);
243 	if (screen_info_video_type(si) != VIDEO_TYPE_VLFB)
244 		return ERR_PTR(-ENODEV);
245 
246 	/*
247 	 * VESA DRM driver
248 	 */
249 
250 	vesa = devm_drm_dev_alloc(&pdev->dev, drv, struct vesadrm_device, sysfb.dev);
251 	if (IS_ERR(vesa))
252 		return ERR_CAST(vesa);
253 	sysfb = &vesa->sysfb;
254 	dev = &sysfb->dev;
255 	platform_set_drvdata(pdev, dev);
256 
257 	/*
258 	 * Hardware settings
259 	 */
260 
261 	format = vesadrm_get_format_si(dev, si);
262 	if (IS_ERR(format))
263 		return ERR_CAST(format);
264 	width = vesadrm_get_width_si(dev, si);
265 	if (width < 0)
266 		return ERR_PTR(width);
267 	height = vesadrm_get_height_si(dev, si);
268 	if (height < 0)
269 		return ERR_PTR(height);
270 	res = vesadrm_get_memory_si(dev, si, &resbuf);
271 	if (!res)
272 		return ERR_PTR(-EINVAL);
273 	stride = vesadrm_get_stride_si(dev, si, format, width, height, resource_size(res));
274 	if (stride < 0)
275 		return ERR_PTR(stride);
276 	vsize = vesadrm_get_visible_size_si(dev, si, height, stride, resource_size(res));
277 	if (!vsize)
278 		return ERR_PTR(-EINVAL);
279 
280 	drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, stride=%d bytes\n",
281 		&format->format, width, height, stride);
282 
283 	sysfb->fb_mode = drm_sysfb_mode(width, height, 0, 0);
284 	sysfb->fb_format = format;
285 	sysfb->fb_pitch = stride;
286 
287 	/*
288 	 * Memory management
289 	 */
290 
291 	ret = devm_aperture_acquire_for_platform_device(pdev, res->start, vsize);
292 	if (ret) {
293 		drm_err(dev, "could not acquire memory range %pr: %d\n", res, ret);
294 		return ERR_PTR(ret);
295 	}
296 
297 	drm_dbg(dev, "using I/O memory framebuffer at %pr\n", res);
298 
299 	mem = devm_request_mem_region(&pdev->dev, res->start, vsize, drv->name);
300 	if (!mem) {
301 		/*
302 		 * We cannot make this fatal. Sometimes this comes from magic
303 		 * spaces our resource handlers simply don't know about. Use
304 		 * the I/O-memory resource as-is and try to map that instead.
305 		 */
306 		drm_warn(dev, "could not acquire memory region %pr\n", res);
307 		mem = res;
308 	}
309 
310 	screen_base = devm_ioremap_wc(&pdev->dev, mem->start, resource_size(mem));
311 	if (!screen_base)
312 		return ERR_PTR(-ENOMEM);
313 	iosys_map_set_vaddr_iomem(&sysfb->fb_addr, screen_base);
314 
315 	/*
316 	 * Modesetting
317 	 */
318 
319 	ret = drmm_mode_config_init(dev);
320 	if (ret)
321 		return ERR_PTR(ret);
322 
323 	max_width = max_t(unsigned long, width, DRM_SHADOW_PLANE_MAX_WIDTH);
324 	max_height = max_t(unsigned long, height, DRM_SHADOW_PLANE_MAX_HEIGHT);
325 
326 	dev->mode_config.min_width = width;
327 	dev->mode_config.max_width = max_width;
328 	dev->mode_config.min_height = height;
329 	dev->mode_config.max_height = max_height;
330 	dev->mode_config.preferred_depth = format->depth;
331 	dev->mode_config.funcs = &vesadrm_mode_config_funcs;
332 
333 	/* Primary plane */
334 
335 	nformats = drm_fb_build_fourcc_list(dev, &format->format, 1,
336 					    vesa->formats, ARRAY_SIZE(vesa->formats));
337 
338 	primary_plane = &vesa->primary_plane;
339 	ret = drm_universal_plane_init(dev, primary_plane, 0, &vesadrm_primary_plane_funcs,
340 				       vesa->formats, nformats,
341 				       vesadrm_primary_plane_format_modifiers,
342 				       DRM_PLANE_TYPE_PRIMARY, NULL);
343 	if (ret)
344 		return ERR_PTR(ret);
345 	drm_plane_helper_add(primary_plane, &vesadrm_primary_plane_helper_funcs);
346 	drm_plane_enable_fb_damage_clips(primary_plane);
347 
348 	/* CRTC */
349 
350 	crtc = &vesa->crtc;
351 	ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
352 					&vesadrm_crtc_funcs, NULL);
353 	if (ret)
354 		return ERR_PTR(ret);
355 	drm_crtc_helper_add(crtc, &vesadrm_crtc_helper_funcs);
356 
357 	/* Encoder */
358 
359 	encoder = &vesa->encoder;
360 	ret = drm_encoder_init(dev, encoder, &vesadrm_encoder_funcs,
361 			       DRM_MODE_ENCODER_NONE, NULL);
362 	if (ret)
363 		return ERR_PTR(ret);
364 	encoder->possible_crtcs = drm_crtc_mask(crtc);
365 
366 	/* Connector */
367 
368 	connector = &vesa->connector;
369 	ret = drm_connector_init(dev, connector, &vesadrm_connector_funcs,
370 				 DRM_MODE_CONNECTOR_Unknown);
371 	if (ret)
372 		return ERR_PTR(ret);
373 	drm_connector_helper_add(connector, &vesadrm_connector_helper_funcs);
374 	drm_connector_set_panel_orientation_with_quirk(connector,
375 						       DRM_MODE_PANEL_ORIENTATION_UNKNOWN,
376 						       width, height);
377 
378 	ret = drm_connector_attach_encoder(connector, encoder);
379 	if (ret)
380 		return ERR_PTR(ret);
381 
382 	drm_mode_config_reset(dev);
383 
384 	return vesa;
385 }
386 
387 /*
388  * DRM driver
389  */
390 
391 DEFINE_DRM_GEM_FOPS(vesadrm_fops);
392 
393 static struct drm_driver vesadrm_driver = {
394 	DRM_GEM_SHMEM_DRIVER_OPS,
395 	DRM_FBDEV_SHMEM_DRIVER_OPS,
396 	.name			= DRIVER_NAME,
397 	.desc			= DRIVER_DESC,
398 	.major			= DRIVER_MAJOR,
399 	.minor			= DRIVER_MINOR,
400 	.driver_features	= DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET,
401 	.fops			= &vesadrm_fops,
402 };
403 
404 /*
405  * Platform driver
406  */
407 
408 static int vesadrm_probe(struct platform_device *pdev)
409 {
410 	struct vesadrm_device *vesa;
411 	struct drm_sysfb_device *sysfb;
412 	struct drm_device *dev;
413 	int ret;
414 
415 	vesa = vesadrm_device_create(&vesadrm_driver, pdev);
416 	if (IS_ERR(vesa))
417 		return PTR_ERR(vesa);
418 	sysfb = &vesa->sysfb;
419 	dev = &sysfb->dev;
420 
421 	ret = drm_dev_register(dev, 0);
422 	if (ret)
423 		return ret;
424 
425 	drm_client_setup(dev, sysfb->fb_format);
426 
427 	return 0;
428 }
429 
430 static void vesadrm_remove(struct platform_device *pdev)
431 {
432 	struct drm_device *dev = platform_get_drvdata(pdev);
433 
434 	drm_dev_unplug(dev);
435 }
436 
437 static struct platform_driver vesadrm_platform_driver = {
438 	.driver = {
439 		.name = "vesa-framebuffer",
440 	},
441 	.probe = vesadrm_probe,
442 	.remove = vesadrm_remove,
443 };
444 
445 module_platform_driver(vesadrm_platform_driver);
446 
447 MODULE_DESCRIPTION(DRIVER_DESC);
448 MODULE_LICENSE("GPL");
449