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", ¶ms->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", ¶ms->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", ¶ms->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, ¶ms->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(¶ms->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(¶ms->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, ¶ms);542 else if (pdev->dev.of_node)543 ret = simplefb_parse_dt(pdev, ¶ms);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 = ¶ms.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