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