brintos

brintos / linux-shallow public Read only

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