882 lines · 23.1 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only #include <linux/clk.h>#include <linux/of_clk.h>#include <linux/minmax.h>#include <linux/platform_data/simplefb.h>#include <linux/platform_device.h>#include <linux/regulator/consumer.h> #include <drm/drm_aperture.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_fb_helper.h>#include <drm/drm_format_helper.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_vtables.h>#include <drm/drm_plane_helper.h>#include <drm/drm_probe_helper.h> #define DRIVER_NAME	"simpledrm"#define DRIVER_DESC	"DRM driver for simple-framebuffer platform devices"#define DRIVER_DATE	"20200625"#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){	if (value > INT_MAX) {		drm_err(dev, "simplefb: invalid framebuffer %s of %u\n",			name, value);		return -EINVAL;	}	return (int)value;} static intsimplefb_get_validated_int0(struct drm_device *dev, const char *name,			    uint32_t value){	if (!value) {		drm_err(dev, "simplefb: invalid framebuffer %s of %u\n",			name, value);		return -EINVAL;	}	return simplefb_get_validated_int(dev, name, value);} 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);} /* * Simple Framebuffer device */ struct simpledrm_device {	struct drm_device dev; 	/* 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 	/* simplefb settings */	struct drm_display_mode mode;	const struct drm_format_info *format;	unsigned int pitch; 	/* memory management */	void __iomem *screen_base; 	/* modesetting */	uint32_t formats[8];	size_t nformats;	struct drm_plane primary_plane;	struct drm_crtc crtc;	struct drm_encoder encoder;	struct drm_connector connector;}; static struct simpledrm_device *simpledrm_device_of_dev(struct drm_device *dev){	return container_of(dev, struct simpledrm_device, dev);} /* * 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 = simpledrm_device_of_dev(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->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 = simpledrm_device_of_dev(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->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 /* * Modesetting */ /* * Support all formats of simplefb and maybe more; in order * of preference. The display's update function will do any * conversion necessary. * * TODO: Add blit helpers for remaining formats and uncomment *       constants. */static const uint32_t simpledrm_primary_plane_formats[] = {	DRM_FORMAT_XRGB8888,	DRM_FORMAT_ARGB8888,	DRM_FORMAT_RGB565,	//DRM_FORMAT_XRGB1555,	//DRM_FORMAT_ARGB1555,	DRM_FORMAT_RGB888,	DRM_FORMAT_XRGB2101010,	DRM_FORMAT_ARGB2101010,}; static const uint64_t simpledrm_primary_plane_format_modifiers[] = {	DRM_FORMAT_MOD_LINEAR,	DRM_FORMAT_MOD_INVALID}; static void simpledrm_primary_plane_helper_atomic_update(struct drm_plane *plane,							 struct drm_atomic_state *state){	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);	struct drm_framebuffer *fb = plane_state->fb;	struct drm_device *dev = plane->dev;	struct simpledrm_device *sdev = simpledrm_device_of_dev(dev);	struct drm_atomic_helper_damage_iter iter;	struct drm_rect damage;	int ret, idx; 	ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);	if (ret)		return; 	if (!drm_dev_enter(dev, &idx))		goto out_drm_gem_fb_end_cpu_access; 	drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);	drm_atomic_for_each_plane_damage(&iter, &damage) {		struct iosys_map dst = IOSYS_MAP_INIT_VADDR(sdev->screen_base);		struct drm_rect dst_clip = plane_state->dst; 		if (!drm_rect_intersect(&dst_clip, &damage))			continue; 		iosys_map_incr(&dst, drm_fb_clip_offset(sdev->pitch, sdev->format, &dst_clip));

Lines 1–500 of 882.