906 lines · 23.6 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only #include <linux/aperture.h>#include <linux/clk.h>#include <linux/minmax.h>#include <linux/of_address.h>#include <linux/of_clk.h>#include <linux/of_reserved_mem.h>#include <linux/platform_data/simplefb.h>#include <linux/platform_device.h>#include <linux/pm.h>#include <linux/pm_domain.h>#include <linux/regulator/consumer.h> #include <drm/clients/drm_client_setup.h>#include <drm/drm_atomic.h>#include <drm/drm_atomic_state_helper.h>#include <drm/drm_connector.h>#include <drm/drm_damage_helper.h>#include <drm/drm_device.h>#include <drm/drm_drv.h>#include <drm/drm_fbdev_shmem.h>#include <drm/drm_framebuffer.h>#include <drm/drm_gem_atomic_helper.h>#include <drm/drm_gem_framebuffer_helper.h>#include <drm/drm_gem_shmem_helper.h>#include <drm/drm_managed.h>#include <drm/drm_modeset_helper.h>#include <drm/drm_modeset_helper_vtables.h>#include <drm/drm_print.h>#include <drm/drm_probe_helper.h> #include "drm_sysfb_helper.h" #define DRIVER_NAME	"simpledrm"#define DRIVER_DESC	"DRM driver for simple-framebuffer platform devices"#define DRIVER_MAJOR	1#define DRIVER_MINOR	0 /* * Helpers for simplefb */ static intsimplefb_get_validated_int(struct drm_device *dev, const char *name,			   uint32_t value){	return drm_sysfb_get_validated_int(dev, name, value, INT_MAX);} static intsimplefb_get_validated_int0(struct drm_device *dev, const char *name,			    uint32_t value){	return drm_sysfb_get_validated_int0(dev, name, value, INT_MAX);} static const struct drm_format_info *simplefb_get_validated_format(struct drm_device *dev, const char *format_name){	static const struct simplefb_format formats[] = SIMPLEFB_FORMATS;	const struct simplefb_format *fmt = formats;	const struct simplefb_format *end = fmt + ARRAY_SIZE(formats);	const struct drm_format_info *info; 	if (!format_name) {		drm_err(dev, "simplefb: missing framebuffer format\n");		return ERR_PTR(-EINVAL);	} 	while (fmt < end) {		if (!strcmp(format_name, fmt->name)) {			info = drm_format_info(fmt->fourcc);			if (!info)				return ERR_PTR(-EINVAL);			return info;		}		++fmt;	} 	drm_err(dev, "simplefb: unknown framebuffer format %s\n",		format_name); 	return ERR_PTR(-EINVAL);} static intsimplefb_get_width_pd(struct drm_device *dev,		      const struct simplefb_platform_data *pd){	return simplefb_get_validated_int0(dev, "width", pd->width);} static intsimplefb_get_height_pd(struct drm_device *dev,		       const struct simplefb_platform_data *pd){	return simplefb_get_validated_int0(dev, "height", pd->height);} static intsimplefb_get_stride_pd(struct drm_device *dev,		       const struct simplefb_platform_data *pd){	return simplefb_get_validated_int(dev, "stride", pd->stride);} static const struct drm_format_info *simplefb_get_format_pd(struct drm_device *dev,		       const struct simplefb_platform_data *pd){	return simplefb_get_validated_format(dev, pd->format);} static intsimplefb_read_u32_of(struct drm_device *dev, struct device_node *of_node,		     const char *name, u32 *value){	int ret = of_property_read_u32(of_node, name, value); 	if (ret)		drm_err(dev, "simplefb: cannot parse framebuffer %s: error %d\n",			name, ret);	return ret;} static intsimplefb_read_string_of(struct drm_device *dev, struct device_node *of_node,			const char *name, const char **value){	int ret = of_property_read_string(of_node, name, value); 	if (ret)		drm_err(dev, "simplefb: cannot parse framebuffer %s: error %d\n",			name, ret);	return ret;} static intsimplefb_get_width_of(struct drm_device *dev, struct device_node *of_node){	u32 width;	int ret = simplefb_read_u32_of(dev, of_node, "width", &width); 	if (ret)		return ret;	return simplefb_get_validated_int0(dev, "width", width);} static intsimplefb_get_height_of(struct drm_device *dev, struct device_node *of_node){	u32 height;	int ret = simplefb_read_u32_of(dev, of_node, "height", &height); 	if (ret)		return ret;	return simplefb_get_validated_int0(dev, "height", height);} static intsimplefb_get_stride_of(struct drm_device *dev, struct device_node *of_node){	u32 stride;	int ret = simplefb_read_u32_of(dev, of_node, "stride", &stride); 	if (ret)		return ret;	return simplefb_get_validated_int(dev, "stride", stride);} static const struct drm_format_info *simplefb_get_format_of(struct drm_device *dev, struct device_node *of_node){	const char *format;	int ret = simplefb_read_string_of(dev, of_node, "format", &format); 	if (ret)		return ERR_PTR(ret);	return simplefb_get_validated_format(dev, format);} static struct resource *simplefb_get_memory_of(struct drm_device *dev, struct device_node *of_node){	struct resource r, *res;	int err; 	err = of_reserved_mem_region_to_resource(of_node, 0, &r);	if (err)		return NULL; 	res = devm_kmemdup(dev->dev, &r, sizeof(r), GFP_KERNEL);	if (!res)		return ERR_PTR(-ENOMEM); 	if (of_property_present(of_node, "reg"))		drm_warn(dev, "preferring \"memory-region\" over \"reg\" property\n"); 	return res;} /* * Simple Framebuffer device */ struct simpledrm_device {	struct drm_sysfb_device sysfb; 	/* clocks */#if defined CONFIG_OF && defined CONFIG_COMMON_CLK	unsigned int clk_count;	struct clk **clks;#endif	/* regulators */#if defined CONFIG_OF && defined CONFIG_REGULATOR	unsigned int regulator_count;	struct regulator **regulators;#endif	/* power-domains */#if defined CONFIG_OF && defined CONFIG_PM_GENERIC_DOMAINS	int pwr_dom_count;	struct device **pwr_dom_devs;	struct device_link **pwr_dom_links;#endif 	/* modesetting */	u32 formats[DRM_SYSFB_PLANE_NFORMATS(1)];	struct drm_plane primary_plane;	struct drm_crtc crtc;	struct drm_encoder encoder;	struct drm_connector connector;}; /* * Hardware */ #if defined CONFIG_OF && defined CONFIG_COMMON_CLK/* * Clock handling code. * * Here we handle the clocks property of our "simple-framebuffer" dt node. * This is necessary so that we can make sure that any clocks needed by * the display engine that the bootloader set up for us (and for which it * provided a simplefb dt node), stay up, for the life of the simplefb * driver. * * When the driver unloads, we cleanly disable, and then release the clocks. * * We only complain about errors here, no action is taken as the most likely * error can only happen due to a mismatch between the bootloader which set * up simplefb, and the clock definitions in the device tree. Chances are * that there are no adverse effects, and if there are, a clean teardown of * the fb probe will not help us much either. So just complain and carry on, * and hope that the user actually gets a working fb at the end of things. */ static void simpledrm_device_release_clocks(void *res){	struct simpledrm_device *sdev = res;	unsigned int i; 	for (i = 0; i < sdev->clk_count; ++i) {		if (sdev->clks[i]) {			clk_disable_unprepare(sdev->clks[i]);			clk_put(sdev->clks[i]);		}	}} static int simpledrm_device_init_clocks(struct simpledrm_device *sdev){	struct drm_device *dev = &sdev->sysfb.dev;	struct platform_device *pdev = to_platform_device(dev->dev);	struct device_node *of_node = pdev->dev.of_node;	struct clk *clock;	unsigned int i;	int ret; 	if (dev_get_platdata(&pdev->dev) || !of_node)		return 0; 	sdev->clk_count = of_clk_get_parent_count(of_node);	if (!sdev->clk_count)		return 0; 	sdev->clks = drmm_kzalloc(dev, sdev->clk_count * sizeof(sdev->clks[0]),				  GFP_KERNEL);	if (!sdev->clks)		return -ENOMEM; 	for (i = 0; i < sdev->clk_count; ++i) {		clock = of_clk_get(of_node, i);		if (IS_ERR(clock)) {			ret = PTR_ERR(clock);			if (ret == -EPROBE_DEFER)				goto err;			drm_err(dev, "clock %u not found: %d\n", i, ret);			continue;		}		ret = clk_prepare_enable(clock);		if (ret) {			drm_err(dev, "failed to enable clock %u: %d\n",				i, ret);			clk_put(clock);			continue;		}		sdev->clks[i] = clock;	} 	return devm_add_action_or_reset(&pdev->dev,					simpledrm_device_release_clocks,					sdev); err:	while (i) {		--i;		if (sdev->clks[i]) {			clk_disable_unprepare(sdev->clks[i]);			clk_put(sdev->clks[i]);		}	}	return ret;}#elsestatic int simpledrm_device_init_clocks(struct simpledrm_device *sdev){	return 0;}#endif #if defined CONFIG_OF && defined CONFIG_REGULATOR #define SUPPLY_SUFFIX "-supply" /* * Regulator handling code. * * Here we handle the num-supplies and vin*-supply properties of our * "simple-framebuffer" dt node. This is necessary so that we can make sure * that any regulators needed by the display hardware that the bootloader * set up for us (and for which it provided a simplefb dt node), stay up, * for the life of the simplefb driver. * * When the driver unloads, we cleanly disable, and then release the * regulators. * * We only complain about errors here, no action is taken as the most likely * error can only happen due to a mismatch between the bootloader which set * up simplefb, and the regulator definitions in the device tree. Chances are * that there are no adverse effects, and if there are, a clean teardown of * the fb probe will not help us much either. So just complain and carry on, * and hope that the user actually gets a working fb at the end of things. */ static void simpledrm_device_release_regulators(void *res){	struct simpledrm_device *sdev = res;	unsigned int i; 	for (i = 0; i < sdev->regulator_count; ++i) {		if (sdev->regulators[i]) {			regulator_disable(sdev->regulators[i]);			regulator_put(sdev->regulators[i]);		}	}} static int simpledrm_device_init_regulators(struct simpledrm_device *sdev){	struct drm_device *dev = &sdev->sysfb.dev;	struct platform_device *pdev = to_platform_device(dev->dev);	struct device_node *of_node = pdev->dev.of_node;	struct property *prop;	struct regulator *regulator;	const char *p;	unsigned int count = 0, i = 0;	int ret; 	if (dev_get_platdata(&pdev->dev) || !of_node)		return 0; 	/* Count the number of regulator supplies */	for_each_property_of_node(of_node, prop) {		p = strstr(prop->name, SUPPLY_SUFFIX);		if (p && p != prop->name)			++count;	} 	if (!count)		return 0; 	sdev->regulators = drmm_kzalloc(dev,					count * sizeof(sdev->regulators[0]),					GFP_KERNEL);	if (!sdev->regulators)		return -ENOMEM; 	for_each_property_of_node(of_node, prop) {		char name[32]; /* 32 is max size of property name */		size_t len; 		p = strstr(prop->name, SUPPLY_SUFFIX);		if (!p || p == prop->name)			continue;		len = strlen(prop->name) - strlen(SUPPLY_SUFFIX) + 1;		strscpy(name, prop->name, min(sizeof(name), len)); 		regulator = regulator_get_optional(&pdev->dev, name);		if (IS_ERR(regulator)) {			ret = PTR_ERR(regulator);			if (ret == -EPROBE_DEFER)				goto err;			drm_err(dev, "regulator %s not found: %d\n",				name, ret);			continue;		} 		ret = regulator_enable(regulator);		if (ret) {			drm_err(dev, "failed to enable regulator %u: %d\n",				i, ret);			regulator_put(regulator);			continue;		} 		sdev->regulators[i++] = regulator;	}	sdev->regulator_count = i; 	return devm_add_action_or_reset(&pdev->dev,					simpledrm_device_release_regulators,					sdev); err:	while (i) {		--i;		if (sdev->regulators[i]) {			regulator_disable(sdev->regulators[i]);			regulator_put(sdev->regulators[i]);		}	}	return ret;}#elsestatic int simpledrm_device_init_regulators(struct simpledrm_device *sdev){	return 0;}#endif #if defined CONFIG_OF && defined CONFIG_PM_GENERIC_DOMAINS/* * Generic power domain handling code. * * Here we handle the power-domains properties of our "simple-framebuffer" * dt node. This is only necessary if there is more than one power-domain. * A single power-domains is handled automatically by the driver core. Multiple * power-domains have to be handled by drivers since the driver core can't know * the correct power sequencing. Power sequencing is not an issue for simpledrm * since the bootloader has put the power domains already in the correct state. * simpledrm has only to ensure they remain active for its lifetime. * * When the driver unloads, we detach from the power-domains. * * We only complain about errors here, no action is taken as the most likely * error can only happen due to a mismatch between the bootloader which set * up the "simple-framebuffer" dt node, and the PM domain providers in the * device tree. Chances are that there are no adverse effects, and if there are, * a clean teardown of the fb probe will not help us much either. So just * complain and carry on, and hope that the user actually gets a working fb at * the end of things. */static void simpledrm_device_detach_genpd(void *res){	int i;	struct simpledrm_device *sdev = res; 	if (sdev->pwr_dom_count <= 1)		return; 	for (i = sdev->pwr_dom_count - 1; i >= 0; i--) {		if (sdev->pwr_dom_links[i])			device_link_del(sdev->pwr_dom_links[i]);		if (!IS_ERR_OR_NULL(sdev->pwr_dom_devs[i]))			dev_pm_domain_detach(sdev->pwr_dom_devs[i], true);	}} static int simpledrm_device_attach_genpd(struct simpledrm_device *sdev){	struct device *dev = sdev->sysfb.dev.dev;	int i; 	sdev->pwr_dom_count = of_count_phandle_with_args(dev->of_node, "power-domains",							 "#power-domain-cells");	/*	 * Single power-domain devices are handled by driver core nothing to do	 * here. The same for device nodes without "power-domains" property.

Lines 1–500 of 906.