brintos

brintos / linux-shallow public Read only

0
0
Text · 17.3 KiB · be95fcd Raw
688 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Simplest possible simple frame-buffer driver, as a platform device4 *5 * Copyright (c) 2013, Stephen Warren6 *7 * Based on q40fb.c, which was:8 * Copyright (C) 2001 Richard Zidlicky <rz@linux-m68k.org>9 *10 * Also based on offb.c, which was:11 * Copyright (C) 1997 Geert Uytterhoeven12 * Copyright (C) 1996 Paul Mackerras13 */14 15#include <linux/aperture.h>16#include <linux/errno.h>17#include <linux/fb.h>18#include <linux/io.h>19#include <linux/module.h>20#include <linux/platform_data/simplefb.h>21#include <linux/platform_device.h>22#include <linux/clk.h>23#include <linux/of.h>24#include <linux/of_address.h>25#include <linux/of_clk.h>26#include <linux/of_platform.h>27#include <linux/parser.h>28#include <linux/pm_domain.h>29#include <linux/regulator/consumer.h>30 31static const struct fb_fix_screeninfo simplefb_fix = {32	.id		= "simple",33	.type		= FB_TYPE_PACKED_PIXELS,34	.visual		= FB_VISUAL_TRUECOLOR,35	.accel		= FB_ACCEL_NONE,36};37 38static const struct fb_var_screeninfo simplefb_var = {39	.height		= -1,40	.width		= -1,41	.activate	= FB_ACTIVATE_NOW,42	.vmode		= FB_VMODE_NONINTERLACED,43};44 45#define PSEUDO_PALETTE_SIZE 1646 47static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,48			      u_int transp, struct fb_info *info)49{50	u32 *pal = info->pseudo_palette;51	u32 cr = red >> (16 - info->var.red.length);52	u32 cg = green >> (16 - info->var.green.length);53	u32 cb = blue >> (16 - info->var.blue.length);54	u32 value;55 56	if (regno >= PSEUDO_PALETTE_SIZE)57		return -EINVAL;58 59	value = (cr << info->var.red.offset) |60		(cg << info->var.green.offset) |61		(cb << info->var.blue.offset);62	if (info->var.transp.length > 0) {63		u32 mask = (1 << info->var.transp.length) - 1;64		mask <<= info->var.transp.offset;65		value |= mask;66	}67	pal[regno] = value;68 69	return 0;70}71 72struct simplefb_par {73	u32 palette[PSEUDO_PALETTE_SIZE];74	resource_size_t base;75	resource_size_t size;76	struct resource *mem;77#if defined CONFIG_OF && defined CONFIG_COMMON_CLK78	bool clks_enabled;79	unsigned int clk_count;80	struct clk **clks;81#endif82#if defined CONFIG_OF && defined CONFIG_PM_GENERIC_DOMAINS83	unsigned int num_genpds;84	struct device **genpds;85	struct device_link **genpd_links;86#endif87#if defined CONFIG_OF && defined CONFIG_REGULATOR88	bool regulators_enabled;89	u32 regulator_count;90	struct regulator **regulators;91#endif92};93 94static void simplefb_clocks_destroy(struct simplefb_par *par);95static void simplefb_regulators_destroy(struct simplefb_par *par);96 97/*98 * fb_ops.fb_destroy is called by the last put_fb_info() call at the end99 * of unregister_framebuffer() or fb_release(). Do any cleanup here.100 */101static void simplefb_destroy(struct fb_info *info)102{103	struct simplefb_par *par = info->par;104	struct resource *mem = par->mem;105 106	simplefb_regulators_destroy(info->par);107	simplefb_clocks_destroy(info->par);108	if (info->screen_base)109		iounmap(info->screen_base);110 111	framebuffer_release(info);112 113	if (mem)114		release_mem_region(mem->start, resource_size(mem));115}116 117static const struct fb_ops simplefb_ops = {118	.owner		= THIS_MODULE,119	FB_DEFAULT_IOMEM_OPS,120	.fb_destroy	= simplefb_destroy,121	.fb_setcolreg	= simplefb_setcolreg,122};123 124static struct simplefb_format simplefb_formats[] = SIMPLEFB_FORMATS;125 126struct simplefb_params {127	u32 width;128	u32 height;129	u32 stride;130	struct simplefb_format *format;131	struct resource memory;132};133 134static int simplefb_parse_dt(struct platform_device *pdev,135			   struct simplefb_params *params)136{137	struct device_node *np = pdev->dev.of_node, *mem;138	int ret;139	const char *format;140	int i;141 142	ret = of_property_read_u32(np, "width", &params->width);143	if (ret) {144		dev_err(&pdev->dev, "Can't parse width property\n");145		return ret;146	}147 148	ret = of_property_read_u32(np, "height", &params->height);149	if (ret) {150		dev_err(&pdev->dev, "Can't parse height property\n");151		return ret;152	}153 154	ret = of_property_read_u32(np, "stride", &params->stride);155	if (ret) {156		dev_err(&pdev->dev, "Can't parse stride property\n");157		return ret;158	}159 160	ret = of_property_read_string(np, "format", &format);161	if (ret) {162		dev_err(&pdev->dev, "Can't parse format property\n");163		return ret;164	}165	params->format = NULL;166	for (i = 0; i < ARRAY_SIZE(simplefb_formats); i++) {167		if (strcmp(format, simplefb_formats[i].name))168			continue;169		params->format = &simplefb_formats[i];170		break;171	}172	if (!params->format) {173		dev_err(&pdev->dev, "Invalid format value\n");174		return -EINVAL;175	}176 177	mem = of_parse_phandle(np, "memory-region", 0);178	if (mem) {179		ret = of_address_to_resource(mem, 0, &params->memory);180		if (ret < 0) {181			dev_err(&pdev->dev, "failed to parse memory-region\n");182			of_node_put(mem);183			return ret;184		}185 186		if (of_property_present(np, "reg"))187			dev_warn(&pdev->dev, "preferring \"memory-region\" over \"reg\" property\n");188 189		of_node_put(mem);190	} else {191		memset(&params->memory, 0, sizeof(params->memory));192	}193 194	return 0;195}196 197static int simplefb_parse_pd(struct platform_device *pdev,198			     struct simplefb_params *params)199{200	struct simplefb_platform_data *pd = dev_get_platdata(&pdev->dev);201	int i;202 203	params->width = pd->width;204	params->height = pd->height;205	params->stride = pd->stride;206 207	params->format = NULL;208	for (i = 0; i < ARRAY_SIZE(simplefb_formats); i++) {209		if (strcmp(pd->format, simplefb_formats[i].name))210			continue;211 212		params->format = &simplefb_formats[i];213		break;214	}215 216	if (!params->format) {217		dev_err(&pdev->dev, "Invalid format value\n");218		return -EINVAL;219	}220 221	memset(&params->memory, 0, sizeof(params->memory));222 223	return 0;224}225 226#if defined CONFIG_OF && defined CONFIG_COMMON_CLK227/*228 * Clock handling code.229 *230 * Here we handle the clocks property of our "simple-framebuffer" dt node.231 * This is necessary so that we can make sure that any clocks needed by232 * the display engine that the bootloader set up for us (and for which it233 * provided a simplefb dt node), stay up, for the life of the simplefb234 * driver.235 *236 * When the driver unloads, we cleanly disable, and then release the clocks.237 *238 * We only complain about errors here, no action is taken as the most likely239 * error can only happen due to a mismatch between the bootloader which set240 * up simplefb, and the clock definitions in the device tree. Chances are241 * that there are no adverse effects, and if there are, a clean teardown of242 * the fb probe will not help us much either. So just complain and carry on,243 * and hope that the user actually gets a working fb at the end of things.244 */245static int simplefb_clocks_get(struct simplefb_par *par,246			       struct platform_device *pdev)247{248	struct device_node *np = pdev->dev.of_node;249	struct clk *clock;250	int i;251 252	if (dev_get_platdata(&pdev->dev) || !np)253		return 0;254 255	par->clk_count = of_clk_get_parent_count(np);256	if (!par->clk_count)257		return 0;258 259	par->clks = kcalloc(par->clk_count, sizeof(struct clk *), GFP_KERNEL);260	if (!par->clks)261		return -ENOMEM;262 263	for (i = 0; i < par->clk_count; i++) {264		clock = of_clk_get(np, i);265		if (IS_ERR(clock)) {266			if (PTR_ERR(clock) == -EPROBE_DEFER) {267				while (--i >= 0) {268					clk_put(par->clks[i]);269				}270				kfree(par->clks);271				return -EPROBE_DEFER;272			}273			dev_err(&pdev->dev, "%s: clock %d not found: %ld\n",274				__func__, i, PTR_ERR(clock));275			continue;276		}277		par->clks[i] = clock;278	}279 280	return 0;281}282 283static void simplefb_clocks_enable(struct simplefb_par *par,284				   struct platform_device *pdev)285{286	int i, ret;287 288	for (i = 0; i < par->clk_count; i++) {289		if (par->clks[i]) {290			ret = clk_prepare_enable(par->clks[i]);291			if (ret) {292				dev_err(&pdev->dev,293					"%s: failed to enable clock %d: %d\n",294					__func__, i, ret);295				clk_put(par->clks[i]);296				par->clks[i] = NULL;297			}298		}299	}300	par->clks_enabled = true;301}302 303static void simplefb_clocks_destroy(struct simplefb_par *par)304{305	int i;306 307	if (!par->clks)308		return;309 310	for (i = 0; i < par->clk_count; i++) {311		if (par->clks[i]) {312			if (par->clks_enabled)313				clk_disable_unprepare(par->clks[i]);314			clk_put(par->clks[i]);315		}316	}317 318	kfree(par->clks);319}320#else321static int simplefb_clocks_get(struct simplefb_par *par,322	struct platform_device *pdev) { return 0; }323static void simplefb_clocks_enable(struct simplefb_par *par,324	struct platform_device *pdev) { }325static void simplefb_clocks_destroy(struct simplefb_par *par) { }326#endif327 328#if defined CONFIG_OF && defined CONFIG_REGULATOR329 330#define SUPPLY_SUFFIX "-supply"331 332/*333 * Regulator handling code.334 *335 * Here we handle the num-supplies and vin*-supply properties of our336 * "simple-framebuffer" dt node. This is necessary so that we can make sure337 * that any regulators needed by the display hardware that the bootloader338 * set up for us (and for which it provided a simplefb dt node), stay up,339 * for the life of the simplefb driver.340 *341 * When the driver unloads, we cleanly disable, and then release the342 * regulators.343 *344 * We only complain about errors here, no action is taken as the most likely345 * error can only happen due to a mismatch between the bootloader which set346 * up simplefb, and the regulator definitions in the device tree. Chances are347 * that there are no adverse effects, and if there are, a clean teardown of348 * the fb probe will not help us much either. So just complain and carry on,349 * and hope that the user actually gets a working fb at the end of things.350 */351static int simplefb_regulators_get(struct simplefb_par *par,352				   struct platform_device *pdev)353{354	struct device_node *np = pdev->dev.of_node;355	struct property *prop;356	struct regulator *regulator;357	const char *p;358	int count = 0, i = 0;359 360	if (dev_get_platdata(&pdev->dev) || !np)361		return 0;362 363	/* Count the number of regulator supplies */364	for_each_property_of_node(np, prop) {365		p = strstr(prop->name, SUPPLY_SUFFIX);366		if (p && p != prop->name)367			count++;368	}369 370	if (!count)371		return 0;372 373	par->regulators = devm_kcalloc(&pdev->dev, count,374				       sizeof(struct regulator *), GFP_KERNEL);375	if (!par->regulators)376		return -ENOMEM;377 378	/* Get all the regulators */379	for_each_property_of_node(np, prop) {380		char name[32]; /* 32 is max size of property name */381 382		p = strstr(prop->name, SUPPLY_SUFFIX);383		if (!p || p == prop->name)384			continue;385 386		strscpy(name, prop->name,387			strlen(prop->name) - strlen(SUPPLY_SUFFIX) + 1);388		regulator = devm_regulator_get_optional(&pdev->dev, name);389		if (IS_ERR(regulator)) {390			if (PTR_ERR(regulator) == -EPROBE_DEFER)391				return -EPROBE_DEFER;392			dev_err(&pdev->dev, "regulator %s not found: %ld\n",393				name, PTR_ERR(regulator));394			continue;395		}396		par->regulators[i++] = regulator;397	}398	par->regulator_count = i;399 400	return 0;401}402 403static void simplefb_regulators_enable(struct simplefb_par *par,404				       struct platform_device *pdev)405{406	int i, ret;407 408	/* Enable all the regulators */409	for (i = 0; i < par->regulator_count; i++) {410		ret = regulator_enable(par->regulators[i]);411		if (ret) {412			dev_err(&pdev->dev,413				"failed to enable regulator %d: %d\n",414				i, ret);415			devm_regulator_put(par->regulators[i]);416			par->regulators[i] = NULL;417		}418	}419	par->regulators_enabled = true;420}421 422static void simplefb_regulators_destroy(struct simplefb_par *par)423{424	int i;425 426	if (!par->regulators || !par->regulators_enabled)427		return;428 429	for (i = 0; i < par->regulator_count; i++)430		if (par->regulators[i])431			regulator_disable(par->regulators[i]);432}433#else434static int simplefb_regulators_get(struct simplefb_par *par,435	struct platform_device *pdev) { return 0; }436static void simplefb_regulators_enable(struct simplefb_par *par,437	struct platform_device *pdev) { }438static void simplefb_regulators_destroy(struct simplefb_par *par) { }439#endif440 441#if defined CONFIG_OF && defined CONFIG_PM_GENERIC_DOMAINS442static void simplefb_detach_genpds(void *res)443{444	struct simplefb_par *par = res;445	unsigned int i = par->num_genpds;446 447	if (par->num_genpds <= 1)448		return;449 450	while (i--) {451		if (par->genpd_links[i])452			device_link_del(par->genpd_links[i]);453 454		if (!IS_ERR_OR_NULL(par->genpds[i]))455			dev_pm_domain_detach(par->genpds[i], true);456	}457}458 459static int simplefb_attach_genpds(struct simplefb_par *par,460				  struct platform_device *pdev)461{462	struct device *dev = &pdev->dev;463	unsigned int i;464	int err;465 466	err = of_count_phandle_with_args(dev->of_node, "power-domains",467					 "#power-domain-cells");468	if (err < 0) {469		/* Nothing wrong if optional PDs are missing */470		if (err == -ENOENT)471			return 0;472 473		dev_err(dev, "failed to parse power-domains: %d\n", err);474		return err;475	}476 477	par->num_genpds = err;478 479	/*480	 * Single power-domain devices are handled by the driver core, so481	 * nothing to do here.482	 */483	if (par->num_genpds <= 1)484		return 0;485 486	par->genpds = devm_kcalloc(dev, par->num_genpds, sizeof(*par->genpds),487				   GFP_KERNEL);488	if (!par->genpds)489		return -ENOMEM;490 491	par->genpd_links = devm_kcalloc(dev, par->num_genpds,492					sizeof(*par->genpd_links),493					GFP_KERNEL);494	if (!par->genpd_links)495		return -ENOMEM;496 497	for (i = 0; i < par->num_genpds; i++) {498		par->genpds[i] = dev_pm_domain_attach_by_id(dev, i);499		if (IS_ERR(par->genpds[i])) {500			err = PTR_ERR(par->genpds[i]);501			if (err == -EPROBE_DEFER) {502				simplefb_detach_genpds(par);503				return err;504			}505 506			dev_warn(dev, "failed to attach domain %u: %d\n", i, err);507			continue;508		}509 510		par->genpd_links[i] = device_link_add(dev, par->genpds[i],511						      DL_FLAG_STATELESS |512						      DL_FLAG_PM_RUNTIME |513						      DL_FLAG_RPM_ACTIVE);514		if (!par->genpd_links[i])515			dev_warn(dev, "failed to link power-domain %u\n", i);516	}517 518	return devm_add_action_or_reset(dev, simplefb_detach_genpds, par);519}520#else521static int simplefb_attach_genpds(struct simplefb_par *par,522				  struct platform_device *pdev)523{524	return 0;525}526#endif527 528static int simplefb_probe(struct platform_device *pdev)529{530	int ret;531	struct simplefb_params params;532	struct fb_info *info;533	struct simplefb_par *par;534	struct resource *res, *mem;535 536	if (fb_get_options("simplefb", NULL))537		return -ENODEV;538 539	ret = -ENODEV;540	if (dev_get_platdata(&pdev->dev))541		ret = simplefb_parse_pd(pdev, &params);542	else if (pdev->dev.of_node)543		ret = simplefb_parse_dt(pdev, &params);544 545	if (ret)546		return ret;547 548	if (params.memory.start == 0 && params.memory.end == 0) {549		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);550		if (!res) {551			dev_err(&pdev->dev, "No memory resource\n");552			return -EINVAL;553		}554	} else {555		res = &params.memory;556	}557 558	mem = request_mem_region(res->start, resource_size(res), "simplefb");559	if (!mem) {560		/*561		 * We cannot make this fatal. Sometimes this comes from magic562		 * spaces our resource handlers simply don't know about. Use563		 * the I/O-memory resource as-is and try to map that instead.564		 */565		dev_warn(&pdev->dev, "simplefb: cannot reserve video memory at %pR\n", res);566		mem = res;567	}568 569	info = framebuffer_alloc(sizeof(struct simplefb_par), &pdev->dev);570	if (!info) {571		ret = -ENOMEM;572		goto error_release_mem_region;573	}574	platform_set_drvdata(pdev, info);575 576	par = info->par;577 578	info->fix = simplefb_fix;579	info->fix.smem_start = mem->start;580	info->fix.smem_len = resource_size(mem);581	info->fix.line_length = params.stride;582 583	info->var = simplefb_var;584	info->var.xres = params.width;585	info->var.yres = params.height;586	info->var.xres_virtual = params.width;587	info->var.yres_virtual = params.height;588	info->var.bits_per_pixel = params.format->bits_per_pixel;589	info->var.red = params.format->red;590	info->var.green = params.format->green;591	info->var.blue = params.format->blue;592	info->var.transp = params.format->transp;593 594	par->base = info->fix.smem_start;595	par->size = info->fix.smem_len;596 597	info->fbops = &simplefb_ops;598	info->screen_base = ioremap_wc(info->fix.smem_start,599				       info->fix.smem_len);600	if (!info->screen_base) {601		ret = -ENOMEM;602		goto error_fb_release;603	}604	info->pseudo_palette = par->palette;605 606	ret = simplefb_clocks_get(par, pdev);607	if (ret < 0)608		goto error_unmap;609 610	ret = simplefb_regulators_get(par, pdev);611	if (ret < 0)612		goto error_clocks;613 614	ret = simplefb_attach_genpds(par, pdev);615	if (ret < 0)616		goto error_regulators;617 618	simplefb_clocks_enable(par, pdev);619	simplefb_regulators_enable(par, pdev);620 621	dev_info(&pdev->dev, "framebuffer at 0x%lx, 0x%x bytes\n",622			     info->fix.smem_start, info->fix.smem_len);623	dev_info(&pdev->dev, "format=%s, mode=%dx%dx%d, linelength=%d\n",624			     params.format->name,625			     info->var.xres, info->var.yres,626			     info->var.bits_per_pixel, info->fix.line_length);627 628	if (mem != res)629		par->mem = mem; /* release in clean-up handler */630 631	ret = devm_aperture_acquire_for_platform_device(pdev, par->base, par->size);632	if (ret) {633		dev_err(&pdev->dev, "Unable to acquire aperture: %d\n", ret);634		goto error_regulators;635	}636	ret = register_framebuffer(info);637	if (ret < 0) {638		dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret);639		goto error_regulators;640	}641 642	dev_info(&pdev->dev, "fb%d: simplefb registered!\n", info->node);643 644	return 0;645 646error_regulators:647	simplefb_regulators_destroy(par);648error_clocks:649	simplefb_clocks_destroy(par);650error_unmap:651	iounmap(info->screen_base);652error_fb_release:653	framebuffer_release(info);654error_release_mem_region:655	if (mem != res)656		release_mem_region(mem->start, resource_size(mem));657	return ret;658}659 660static void simplefb_remove(struct platform_device *pdev)661{662	struct fb_info *info = platform_get_drvdata(pdev);663 664	/* simplefb_destroy takes care of info cleanup */665	unregister_framebuffer(info);666}667 668static const struct of_device_id simplefb_of_match[] = {669	{ .compatible = "simple-framebuffer", },670	{ },671};672MODULE_DEVICE_TABLE(of, simplefb_of_match);673 674static struct platform_driver simplefb_driver = {675	.driver = {676		.name = "simple-framebuffer",677		.of_match_table = simplefb_of_match,678	},679	.probe = simplefb_probe,680	.remove = simplefb_remove,681};682 683module_platform_driver(simplefb_driver);684 685MODULE_AUTHOR("Stephen Warren <swarren@wwwdotorg.org>");686MODULE_DESCRIPTION("Simple framebuffer driver");687MODULE_LICENSE("GPL v2");688