1319251c5SThomas Zimmermann // SPDX-License-Identifier: GPL-2.0-only 2319251c5SThomas Zimmermann 3319251c5SThomas Zimmermann #include <linux/aperture.h> 4319251c5SThomas Zimmermann #include <linux/clk.h> 5319251c5SThomas Zimmermann #include <linux/of_clk.h> 6319251c5SThomas Zimmermann #include <linux/minmax.h> 7319251c5SThomas Zimmermann #include <linux/of_address.h> 8319251c5SThomas Zimmermann #include <linux/platform_data/simplefb.h> 9319251c5SThomas Zimmermann #include <linux/platform_device.h> 10319251c5SThomas Zimmermann #include <linux/pm_domain.h> 11319251c5SThomas Zimmermann #include <linux/regulator/consumer.h> 12319251c5SThomas Zimmermann 13319251c5SThomas Zimmermann #include <drm/clients/drm_client_setup.h> 14319251c5SThomas Zimmermann #include <drm/drm_atomic.h> 15319251c5SThomas Zimmermann #include <drm/drm_atomic_state_helper.h> 16319251c5SThomas Zimmermann #include <drm/drm_connector.h> 17319251c5SThomas Zimmermann #include <drm/drm_damage_helper.h> 18319251c5SThomas Zimmermann #include <drm/drm_device.h> 19319251c5SThomas Zimmermann #include <drm/drm_drv.h> 20319251c5SThomas Zimmermann #include <drm/drm_fbdev_shmem.h> 21319251c5SThomas Zimmermann #include <drm/drm_format_helper.h> 22319251c5SThomas Zimmermann #include <drm/drm_framebuffer.h> 23319251c5SThomas Zimmermann #include <drm/drm_gem_atomic_helper.h> 24319251c5SThomas Zimmermann #include <drm/drm_gem_framebuffer_helper.h> 25319251c5SThomas Zimmermann #include <drm/drm_gem_shmem_helper.h> 26319251c5SThomas Zimmermann #include <drm/drm_managed.h> 27319251c5SThomas Zimmermann #include <drm/drm_modeset_helper_vtables.h> 28319251c5SThomas Zimmermann #include <drm/drm_probe_helper.h> 29319251c5SThomas Zimmermann 30b5626f6fSThomas Zimmermann #include "drm_sysfb_helper.h" 31b5626f6fSThomas Zimmermann 32319251c5SThomas Zimmermann #define DRIVER_NAME "simpledrm" 33319251c5SThomas Zimmermann #define DRIVER_DESC "DRM driver for simple-framebuffer platform devices" 34319251c5SThomas Zimmermann #define DRIVER_MAJOR 1 35319251c5SThomas Zimmermann #define DRIVER_MINOR 0 36319251c5SThomas Zimmermann 37319251c5SThomas Zimmermann /* 38319251c5SThomas Zimmermann * Helpers for simplefb 39319251c5SThomas Zimmermann */ 40319251c5SThomas Zimmermann 41319251c5SThomas Zimmermann static int 42319251c5SThomas Zimmermann simplefb_get_validated_int(struct drm_device *dev, const char *name, 43319251c5SThomas Zimmermann uint32_t value) 44319251c5SThomas Zimmermann { 45319251c5SThomas Zimmermann if (value > INT_MAX) { 46319251c5SThomas Zimmermann drm_err(dev, "simplefb: invalid framebuffer %s of %u\n", 47319251c5SThomas Zimmermann name, value); 48319251c5SThomas Zimmermann return -EINVAL; 49319251c5SThomas Zimmermann } 50319251c5SThomas Zimmermann return (int)value; 51319251c5SThomas Zimmermann } 52319251c5SThomas Zimmermann 53319251c5SThomas Zimmermann static int 54319251c5SThomas Zimmermann simplefb_get_validated_int0(struct drm_device *dev, const char *name, 55319251c5SThomas Zimmermann uint32_t value) 56319251c5SThomas Zimmermann { 57319251c5SThomas Zimmermann if (!value) { 58319251c5SThomas Zimmermann drm_err(dev, "simplefb: invalid framebuffer %s of %u\n", 59319251c5SThomas Zimmermann name, value); 60319251c5SThomas Zimmermann return -EINVAL; 61319251c5SThomas Zimmermann } 62319251c5SThomas Zimmermann return simplefb_get_validated_int(dev, name, value); 63319251c5SThomas Zimmermann } 64319251c5SThomas Zimmermann 65319251c5SThomas Zimmermann static const struct drm_format_info * 66319251c5SThomas Zimmermann simplefb_get_validated_format(struct drm_device *dev, const char *format_name) 67319251c5SThomas Zimmermann { 68319251c5SThomas Zimmermann static const struct simplefb_format formats[] = SIMPLEFB_FORMATS; 69319251c5SThomas Zimmermann const struct simplefb_format *fmt = formats; 70319251c5SThomas Zimmermann const struct simplefb_format *end = fmt + ARRAY_SIZE(formats); 71319251c5SThomas Zimmermann const struct drm_format_info *info; 72319251c5SThomas Zimmermann 73319251c5SThomas Zimmermann if (!format_name) { 74319251c5SThomas Zimmermann drm_err(dev, "simplefb: missing framebuffer format\n"); 75319251c5SThomas Zimmermann return ERR_PTR(-EINVAL); 76319251c5SThomas Zimmermann } 77319251c5SThomas Zimmermann 78319251c5SThomas Zimmermann while (fmt < end) { 79319251c5SThomas Zimmermann if (!strcmp(format_name, fmt->name)) { 80319251c5SThomas Zimmermann info = drm_format_info(fmt->fourcc); 81319251c5SThomas Zimmermann if (!info) 82319251c5SThomas Zimmermann return ERR_PTR(-EINVAL); 83319251c5SThomas Zimmermann return info; 84319251c5SThomas Zimmermann } 85319251c5SThomas Zimmermann ++fmt; 86319251c5SThomas Zimmermann } 87319251c5SThomas Zimmermann 88319251c5SThomas Zimmermann drm_err(dev, "simplefb: unknown framebuffer format %s\n", 89319251c5SThomas Zimmermann format_name); 90319251c5SThomas Zimmermann 91319251c5SThomas Zimmermann return ERR_PTR(-EINVAL); 92319251c5SThomas Zimmermann } 93319251c5SThomas Zimmermann 94319251c5SThomas Zimmermann static int 95319251c5SThomas Zimmermann simplefb_get_width_pd(struct drm_device *dev, 96319251c5SThomas Zimmermann const struct simplefb_platform_data *pd) 97319251c5SThomas Zimmermann { 98319251c5SThomas Zimmermann return simplefb_get_validated_int0(dev, "width", pd->width); 99319251c5SThomas Zimmermann } 100319251c5SThomas Zimmermann 101319251c5SThomas Zimmermann static int 102319251c5SThomas Zimmermann simplefb_get_height_pd(struct drm_device *dev, 103319251c5SThomas Zimmermann const struct simplefb_platform_data *pd) 104319251c5SThomas Zimmermann { 105319251c5SThomas Zimmermann return simplefb_get_validated_int0(dev, "height", pd->height); 106319251c5SThomas Zimmermann } 107319251c5SThomas Zimmermann 108319251c5SThomas Zimmermann static int 109319251c5SThomas Zimmermann simplefb_get_stride_pd(struct drm_device *dev, 110319251c5SThomas Zimmermann const struct simplefb_platform_data *pd) 111319251c5SThomas Zimmermann { 112319251c5SThomas Zimmermann return simplefb_get_validated_int(dev, "stride", pd->stride); 113319251c5SThomas Zimmermann } 114319251c5SThomas Zimmermann 115319251c5SThomas Zimmermann static const struct drm_format_info * 116319251c5SThomas Zimmermann simplefb_get_format_pd(struct drm_device *dev, 117319251c5SThomas Zimmermann const struct simplefb_platform_data *pd) 118319251c5SThomas Zimmermann { 119319251c5SThomas Zimmermann return simplefb_get_validated_format(dev, pd->format); 120319251c5SThomas Zimmermann } 121319251c5SThomas Zimmermann 122319251c5SThomas Zimmermann static int 123319251c5SThomas Zimmermann simplefb_read_u32_of(struct drm_device *dev, struct device_node *of_node, 124319251c5SThomas Zimmermann const char *name, u32 *value) 125319251c5SThomas Zimmermann { 126319251c5SThomas Zimmermann int ret = of_property_read_u32(of_node, name, value); 127319251c5SThomas Zimmermann 128319251c5SThomas Zimmermann if (ret) 129319251c5SThomas Zimmermann drm_err(dev, "simplefb: cannot parse framebuffer %s: error %d\n", 130319251c5SThomas Zimmermann name, ret); 131319251c5SThomas Zimmermann return ret; 132319251c5SThomas Zimmermann } 133319251c5SThomas Zimmermann 134319251c5SThomas Zimmermann static int 135319251c5SThomas Zimmermann simplefb_read_string_of(struct drm_device *dev, struct device_node *of_node, 136319251c5SThomas Zimmermann const char *name, const char **value) 137319251c5SThomas Zimmermann { 138319251c5SThomas Zimmermann int ret = of_property_read_string(of_node, name, value); 139319251c5SThomas Zimmermann 140319251c5SThomas Zimmermann if (ret) 141319251c5SThomas Zimmermann drm_err(dev, "simplefb: cannot parse framebuffer %s: error %d\n", 142319251c5SThomas Zimmermann name, ret); 143319251c5SThomas Zimmermann return ret; 144319251c5SThomas Zimmermann } 145319251c5SThomas Zimmermann 146319251c5SThomas Zimmermann static int 147319251c5SThomas Zimmermann simplefb_get_width_of(struct drm_device *dev, struct device_node *of_node) 148319251c5SThomas Zimmermann { 149319251c5SThomas Zimmermann u32 width; 150319251c5SThomas Zimmermann int ret = simplefb_read_u32_of(dev, of_node, "width", &width); 151319251c5SThomas Zimmermann 152319251c5SThomas Zimmermann if (ret) 153319251c5SThomas Zimmermann return ret; 154319251c5SThomas Zimmermann return simplefb_get_validated_int0(dev, "width", width); 155319251c5SThomas Zimmermann } 156319251c5SThomas Zimmermann 157319251c5SThomas Zimmermann static int 158319251c5SThomas Zimmermann simplefb_get_height_of(struct drm_device *dev, struct device_node *of_node) 159319251c5SThomas Zimmermann { 160319251c5SThomas Zimmermann u32 height; 161319251c5SThomas Zimmermann int ret = simplefb_read_u32_of(dev, of_node, "height", &height); 162319251c5SThomas Zimmermann 163319251c5SThomas Zimmermann if (ret) 164319251c5SThomas Zimmermann return ret; 165319251c5SThomas Zimmermann return simplefb_get_validated_int0(dev, "height", height); 166319251c5SThomas Zimmermann } 167319251c5SThomas Zimmermann 168319251c5SThomas Zimmermann static int 169319251c5SThomas Zimmermann simplefb_get_stride_of(struct drm_device *dev, struct device_node *of_node) 170319251c5SThomas Zimmermann { 171319251c5SThomas Zimmermann u32 stride; 172319251c5SThomas Zimmermann int ret = simplefb_read_u32_of(dev, of_node, "stride", &stride); 173319251c5SThomas Zimmermann 174319251c5SThomas Zimmermann if (ret) 175319251c5SThomas Zimmermann return ret; 176319251c5SThomas Zimmermann return simplefb_get_validated_int(dev, "stride", stride); 177319251c5SThomas Zimmermann } 178319251c5SThomas Zimmermann 179319251c5SThomas Zimmermann static const struct drm_format_info * 180319251c5SThomas Zimmermann simplefb_get_format_of(struct drm_device *dev, struct device_node *of_node) 181319251c5SThomas Zimmermann { 182319251c5SThomas Zimmermann const char *format; 183319251c5SThomas Zimmermann int ret = simplefb_read_string_of(dev, of_node, "format", &format); 184319251c5SThomas Zimmermann 185319251c5SThomas Zimmermann if (ret) 186319251c5SThomas Zimmermann return ERR_PTR(ret); 187319251c5SThomas Zimmermann return simplefb_get_validated_format(dev, format); 188319251c5SThomas Zimmermann } 189319251c5SThomas Zimmermann 190319251c5SThomas Zimmermann static struct resource * 191319251c5SThomas Zimmermann simplefb_get_memory_of(struct drm_device *dev, struct device_node *of_node) 192319251c5SThomas Zimmermann { 193319251c5SThomas Zimmermann struct device_node *np; 194319251c5SThomas Zimmermann struct resource *res; 195319251c5SThomas Zimmermann int err; 196319251c5SThomas Zimmermann 197319251c5SThomas Zimmermann np = of_parse_phandle(of_node, "memory-region", 0); 198319251c5SThomas Zimmermann if (!np) 199319251c5SThomas Zimmermann return NULL; 200319251c5SThomas Zimmermann 201319251c5SThomas Zimmermann res = devm_kzalloc(dev->dev, sizeof(*res), GFP_KERNEL); 202319251c5SThomas Zimmermann if (!res) 203319251c5SThomas Zimmermann return ERR_PTR(-ENOMEM); 204319251c5SThomas Zimmermann 205319251c5SThomas Zimmermann err = of_address_to_resource(np, 0, res); 206319251c5SThomas Zimmermann if (err) 207319251c5SThomas Zimmermann return ERR_PTR(err); 208319251c5SThomas Zimmermann 209319251c5SThomas Zimmermann if (of_property_present(of_node, "reg")) 210319251c5SThomas Zimmermann drm_warn(dev, "preferring \"memory-region\" over \"reg\" property\n"); 211319251c5SThomas Zimmermann 212319251c5SThomas Zimmermann return res; 213319251c5SThomas Zimmermann } 214319251c5SThomas Zimmermann 215319251c5SThomas Zimmermann /* 216319251c5SThomas Zimmermann * Simple Framebuffer device 217319251c5SThomas Zimmermann */ 218319251c5SThomas Zimmermann 219319251c5SThomas Zimmermann struct simpledrm_device { 220b5626f6fSThomas Zimmermann struct drm_sysfb_device sysfb; 221319251c5SThomas Zimmermann 222319251c5SThomas Zimmermann /* clocks */ 223319251c5SThomas Zimmermann #if defined CONFIG_OF && defined CONFIG_COMMON_CLK 224319251c5SThomas Zimmermann unsigned int clk_count; 225319251c5SThomas Zimmermann struct clk **clks; 226319251c5SThomas Zimmermann #endif 227319251c5SThomas Zimmermann /* regulators */ 228319251c5SThomas Zimmermann #if defined CONFIG_OF && defined CONFIG_REGULATOR 229319251c5SThomas Zimmermann unsigned int regulator_count; 230319251c5SThomas Zimmermann struct regulator **regulators; 231319251c5SThomas Zimmermann #endif 232319251c5SThomas Zimmermann /* power-domains */ 233319251c5SThomas Zimmermann #if defined CONFIG_OF && defined CONFIG_PM_GENERIC_DOMAINS 234319251c5SThomas Zimmermann int pwr_dom_count; 235319251c5SThomas Zimmermann struct device **pwr_dom_devs; 236319251c5SThomas Zimmermann struct device_link **pwr_dom_links; 237319251c5SThomas Zimmermann #endif 238319251c5SThomas Zimmermann 239319251c5SThomas Zimmermann /* modesetting */ 240*177dfbdbSThomas Zimmermann u32 formats[DRM_SYSFB_PLANE_NFORMATS(1)]; 241319251c5SThomas Zimmermann struct drm_plane primary_plane; 242319251c5SThomas Zimmermann struct drm_crtc crtc; 243319251c5SThomas Zimmermann struct drm_encoder encoder; 244319251c5SThomas Zimmermann struct drm_connector connector; 245319251c5SThomas Zimmermann }; 246319251c5SThomas Zimmermann 247319251c5SThomas Zimmermann static struct simpledrm_device *simpledrm_device_of_dev(struct drm_device *dev) 248319251c5SThomas Zimmermann { 249b5626f6fSThomas Zimmermann return container_of(to_drm_sysfb_device(dev), struct simpledrm_device, sysfb); 250319251c5SThomas Zimmermann } 251319251c5SThomas Zimmermann 252319251c5SThomas Zimmermann /* 253319251c5SThomas Zimmermann * Hardware 254319251c5SThomas Zimmermann */ 255319251c5SThomas Zimmermann 256319251c5SThomas Zimmermann #if defined CONFIG_OF && defined CONFIG_COMMON_CLK 257319251c5SThomas Zimmermann /* 258319251c5SThomas Zimmermann * Clock handling code. 259319251c5SThomas Zimmermann * 260319251c5SThomas Zimmermann * Here we handle the clocks property of our "simple-framebuffer" dt node. 261319251c5SThomas Zimmermann * This is necessary so that we can make sure that any clocks needed by 262319251c5SThomas Zimmermann * the display engine that the bootloader set up for us (and for which it 263319251c5SThomas Zimmermann * provided a simplefb dt node), stay up, for the life of the simplefb 264319251c5SThomas Zimmermann * driver. 265319251c5SThomas Zimmermann * 266319251c5SThomas Zimmermann * When the driver unloads, we cleanly disable, and then release the clocks. 267319251c5SThomas Zimmermann * 268319251c5SThomas Zimmermann * We only complain about errors here, no action is taken as the most likely 269319251c5SThomas Zimmermann * error can only happen due to a mismatch between the bootloader which set 270319251c5SThomas Zimmermann * up simplefb, and the clock definitions in the device tree. Chances are 271319251c5SThomas Zimmermann * that there are no adverse effects, and if there are, a clean teardown of 272319251c5SThomas Zimmermann * the fb probe will not help us much either. So just complain and carry on, 273319251c5SThomas Zimmermann * and hope that the user actually gets a working fb at the end of things. 274319251c5SThomas Zimmermann */ 275319251c5SThomas Zimmermann 276319251c5SThomas Zimmermann static void simpledrm_device_release_clocks(void *res) 277319251c5SThomas Zimmermann { 278319251c5SThomas Zimmermann struct simpledrm_device *sdev = simpledrm_device_of_dev(res); 279319251c5SThomas Zimmermann unsigned int i; 280319251c5SThomas Zimmermann 281319251c5SThomas Zimmermann for (i = 0; i < sdev->clk_count; ++i) { 282319251c5SThomas Zimmermann if (sdev->clks[i]) { 283319251c5SThomas Zimmermann clk_disable_unprepare(sdev->clks[i]); 284319251c5SThomas Zimmermann clk_put(sdev->clks[i]); 285319251c5SThomas Zimmermann } 286319251c5SThomas Zimmermann } 287319251c5SThomas Zimmermann } 288319251c5SThomas Zimmermann 289319251c5SThomas Zimmermann static int simpledrm_device_init_clocks(struct simpledrm_device *sdev) 290319251c5SThomas Zimmermann { 291b5626f6fSThomas Zimmermann struct drm_device *dev = &sdev->sysfb.dev; 292319251c5SThomas Zimmermann struct platform_device *pdev = to_platform_device(dev->dev); 293319251c5SThomas Zimmermann struct device_node *of_node = pdev->dev.of_node; 294319251c5SThomas Zimmermann struct clk *clock; 295319251c5SThomas Zimmermann unsigned int i; 296319251c5SThomas Zimmermann int ret; 297319251c5SThomas Zimmermann 298319251c5SThomas Zimmermann if (dev_get_platdata(&pdev->dev) || !of_node) 299319251c5SThomas Zimmermann return 0; 300319251c5SThomas Zimmermann 301319251c5SThomas Zimmermann sdev->clk_count = of_clk_get_parent_count(of_node); 302319251c5SThomas Zimmermann if (!sdev->clk_count) 303319251c5SThomas Zimmermann return 0; 304319251c5SThomas Zimmermann 305319251c5SThomas Zimmermann sdev->clks = drmm_kzalloc(dev, sdev->clk_count * sizeof(sdev->clks[0]), 306319251c5SThomas Zimmermann GFP_KERNEL); 307319251c5SThomas Zimmermann if (!sdev->clks) 308319251c5SThomas Zimmermann return -ENOMEM; 309319251c5SThomas Zimmermann 310319251c5SThomas Zimmermann for (i = 0; i < sdev->clk_count; ++i) { 311319251c5SThomas Zimmermann clock = of_clk_get(of_node, i); 312319251c5SThomas Zimmermann if (IS_ERR(clock)) { 313319251c5SThomas Zimmermann ret = PTR_ERR(clock); 314319251c5SThomas Zimmermann if (ret == -EPROBE_DEFER) 315319251c5SThomas Zimmermann goto err; 316319251c5SThomas Zimmermann drm_err(dev, "clock %u not found: %d\n", i, ret); 317319251c5SThomas Zimmermann continue; 318319251c5SThomas Zimmermann } 319319251c5SThomas Zimmermann ret = clk_prepare_enable(clock); 320319251c5SThomas Zimmermann if (ret) { 321319251c5SThomas Zimmermann drm_err(dev, "failed to enable clock %u: %d\n", 322319251c5SThomas Zimmermann i, ret); 323319251c5SThomas Zimmermann clk_put(clock); 324319251c5SThomas Zimmermann continue; 325319251c5SThomas Zimmermann } 326319251c5SThomas Zimmermann sdev->clks[i] = clock; 327319251c5SThomas Zimmermann } 328319251c5SThomas Zimmermann 329319251c5SThomas Zimmermann return devm_add_action_or_reset(&pdev->dev, 330319251c5SThomas Zimmermann simpledrm_device_release_clocks, 331319251c5SThomas Zimmermann sdev); 332319251c5SThomas Zimmermann 333319251c5SThomas Zimmermann err: 334319251c5SThomas Zimmermann while (i) { 335319251c5SThomas Zimmermann --i; 336319251c5SThomas Zimmermann if (sdev->clks[i]) { 337319251c5SThomas Zimmermann clk_disable_unprepare(sdev->clks[i]); 338319251c5SThomas Zimmermann clk_put(sdev->clks[i]); 339319251c5SThomas Zimmermann } 340319251c5SThomas Zimmermann } 341319251c5SThomas Zimmermann return ret; 342319251c5SThomas Zimmermann } 343319251c5SThomas Zimmermann #else 344319251c5SThomas Zimmermann static int simpledrm_device_init_clocks(struct simpledrm_device *sdev) 345319251c5SThomas Zimmermann { 346319251c5SThomas Zimmermann return 0; 347319251c5SThomas Zimmermann } 348319251c5SThomas Zimmermann #endif 349319251c5SThomas Zimmermann 350319251c5SThomas Zimmermann #if defined CONFIG_OF && defined CONFIG_REGULATOR 351319251c5SThomas Zimmermann 352319251c5SThomas Zimmermann #define SUPPLY_SUFFIX "-supply" 353319251c5SThomas Zimmermann 354319251c5SThomas Zimmermann /* 355319251c5SThomas Zimmermann * Regulator handling code. 356319251c5SThomas Zimmermann * 357319251c5SThomas Zimmermann * Here we handle the num-supplies and vin*-supply properties of our 358319251c5SThomas Zimmermann * "simple-framebuffer" dt node. This is necessary so that we can make sure 359319251c5SThomas Zimmermann * that any regulators needed by the display hardware that the bootloader 360319251c5SThomas Zimmermann * set up for us (and for which it provided a simplefb dt node), stay up, 361319251c5SThomas Zimmermann * for the life of the simplefb driver. 362319251c5SThomas Zimmermann * 363319251c5SThomas Zimmermann * When the driver unloads, we cleanly disable, and then release the 364319251c5SThomas Zimmermann * regulators. 365319251c5SThomas Zimmermann * 366319251c5SThomas Zimmermann * We only complain about errors here, no action is taken as the most likely 367319251c5SThomas Zimmermann * error can only happen due to a mismatch between the bootloader which set 368319251c5SThomas Zimmermann * up simplefb, and the regulator definitions in the device tree. Chances are 369319251c5SThomas Zimmermann * that there are no adverse effects, and if there are, a clean teardown of 370319251c5SThomas Zimmermann * the fb probe will not help us much either. So just complain and carry on, 371319251c5SThomas Zimmermann * and hope that the user actually gets a working fb at the end of things. 372319251c5SThomas Zimmermann */ 373319251c5SThomas Zimmermann 374319251c5SThomas Zimmermann static void simpledrm_device_release_regulators(void *res) 375319251c5SThomas Zimmermann { 376319251c5SThomas Zimmermann struct simpledrm_device *sdev = simpledrm_device_of_dev(res); 377319251c5SThomas Zimmermann unsigned int i; 378319251c5SThomas Zimmermann 379319251c5SThomas Zimmermann for (i = 0; i < sdev->regulator_count; ++i) { 380319251c5SThomas Zimmermann if (sdev->regulators[i]) { 381319251c5SThomas Zimmermann regulator_disable(sdev->regulators[i]); 382319251c5SThomas Zimmermann regulator_put(sdev->regulators[i]); 383319251c5SThomas Zimmermann } 384319251c5SThomas Zimmermann } 385319251c5SThomas Zimmermann } 386319251c5SThomas Zimmermann 387319251c5SThomas Zimmermann static int simpledrm_device_init_regulators(struct simpledrm_device *sdev) 388319251c5SThomas Zimmermann { 389b5626f6fSThomas Zimmermann struct drm_device *dev = &sdev->sysfb.dev; 390319251c5SThomas Zimmermann struct platform_device *pdev = to_platform_device(dev->dev); 391319251c5SThomas Zimmermann struct device_node *of_node = pdev->dev.of_node; 392319251c5SThomas Zimmermann struct property *prop; 393319251c5SThomas Zimmermann struct regulator *regulator; 394319251c5SThomas Zimmermann const char *p; 395319251c5SThomas Zimmermann unsigned int count = 0, i = 0; 396319251c5SThomas Zimmermann int ret; 397319251c5SThomas Zimmermann 398319251c5SThomas Zimmermann if (dev_get_platdata(&pdev->dev) || !of_node) 399319251c5SThomas Zimmermann return 0; 400319251c5SThomas Zimmermann 401319251c5SThomas Zimmermann /* Count the number of regulator supplies */ 402319251c5SThomas Zimmermann for_each_property_of_node(of_node, prop) { 403319251c5SThomas Zimmermann p = strstr(prop->name, SUPPLY_SUFFIX); 404319251c5SThomas Zimmermann if (p && p != prop->name) 405319251c5SThomas Zimmermann ++count; 406319251c5SThomas Zimmermann } 407319251c5SThomas Zimmermann 408319251c5SThomas Zimmermann if (!count) 409319251c5SThomas Zimmermann return 0; 410319251c5SThomas Zimmermann 411319251c5SThomas Zimmermann sdev->regulators = drmm_kzalloc(dev, 412319251c5SThomas Zimmermann count * sizeof(sdev->regulators[0]), 413319251c5SThomas Zimmermann GFP_KERNEL); 414319251c5SThomas Zimmermann if (!sdev->regulators) 415319251c5SThomas Zimmermann return -ENOMEM; 416319251c5SThomas Zimmermann 417319251c5SThomas Zimmermann for_each_property_of_node(of_node, prop) { 418319251c5SThomas Zimmermann char name[32]; /* 32 is max size of property name */ 419319251c5SThomas Zimmermann size_t len; 420319251c5SThomas Zimmermann 421319251c5SThomas Zimmermann p = strstr(prop->name, SUPPLY_SUFFIX); 422319251c5SThomas Zimmermann if (!p || p == prop->name) 423319251c5SThomas Zimmermann continue; 424319251c5SThomas Zimmermann len = strlen(prop->name) - strlen(SUPPLY_SUFFIX) + 1; 425319251c5SThomas Zimmermann strscpy(name, prop->name, min(sizeof(name), len)); 426319251c5SThomas Zimmermann 427319251c5SThomas Zimmermann regulator = regulator_get_optional(&pdev->dev, name); 428319251c5SThomas Zimmermann if (IS_ERR(regulator)) { 429319251c5SThomas Zimmermann ret = PTR_ERR(regulator); 430319251c5SThomas Zimmermann if (ret == -EPROBE_DEFER) 431319251c5SThomas Zimmermann goto err; 432319251c5SThomas Zimmermann drm_err(dev, "regulator %s not found: %d\n", 433319251c5SThomas Zimmermann name, ret); 434319251c5SThomas Zimmermann continue; 435319251c5SThomas Zimmermann } 436319251c5SThomas Zimmermann 437319251c5SThomas Zimmermann ret = regulator_enable(regulator); 438319251c5SThomas Zimmermann if (ret) { 439319251c5SThomas Zimmermann drm_err(dev, "failed to enable regulator %u: %d\n", 440319251c5SThomas Zimmermann i, ret); 441319251c5SThomas Zimmermann regulator_put(regulator); 442319251c5SThomas Zimmermann continue; 443319251c5SThomas Zimmermann } 444319251c5SThomas Zimmermann 445319251c5SThomas Zimmermann sdev->regulators[i++] = regulator; 446319251c5SThomas Zimmermann } 447319251c5SThomas Zimmermann sdev->regulator_count = i; 448319251c5SThomas Zimmermann 449319251c5SThomas Zimmermann return devm_add_action_or_reset(&pdev->dev, 450319251c5SThomas Zimmermann simpledrm_device_release_regulators, 451319251c5SThomas Zimmermann sdev); 452319251c5SThomas Zimmermann 453319251c5SThomas Zimmermann err: 454319251c5SThomas Zimmermann while (i) { 455319251c5SThomas Zimmermann --i; 456319251c5SThomas Zimmermann if (sdev->regulators[i]) { 457319251c5SThomas Zimmermann regulator_disable(sdev->regulators[i]); 458319251c5SThomas Zimmermann regulator_put(sdev->regulators[i]); 459319251c5SThomas Zimmermann } 460319251c5SThomas Zimmermann } 461319251c5SThomas Zimmermann return ret; 462319251c5SThomas Zimmermann } 463319251c5SThomas Zimmermann #else 464319251c5SThomas Zimmermann static int simpledrm_device_init_regulators(struct simpledrm_device *sdev) 465319251c5SThomas Zimmermann { 466319251c5SThomas Zimmermann return 0; 467319251c5SThomas Zimmermann } 468319251c5SThomas Zimmermann #endif 469319251c5SThomas Zimmermann 470319251c5SThomas Zimmermann #if defined CONFIG_OF && defined CONFIG_PM_GENERIC_DOMAINS 471319251c5SThomas Zimmermann /* 472319251c5SThomas Zimmermann * Generic power domain handling code. 473319251c5SThomas Zimmermann * 474319251c5SThomas Zimmermann * Here we handle the power-domains properties of our "simple-framebuffer" 475319251c5SThomas Zimmermann * dt node. This is only necessary if there is more than one power-domain. 476319251c5SThomas Zimmermann * A single power-domains is handled automatically by the driver core. Multiple 477319251c5SThomas Zimmermann * power-domains have to be handled by drivers since the driver core can't know 478319251c5SThomas Zimmermann * the correct power sequencing. Power sequencing is not an issue for simpledrm 479319251c5SThomas Zimmermann * since the bootloader has put the power domains already in the correct state. 480319251c5SThomas Zimmermann * simpledrm has only to ensure they remain active for its lifetime. 481319251c5SThomas Zimmermann * 482319251c5SThomas Zimmermann * When the driver unloads, we detach from the power-domains. 483319251c5SThomas Zimmermann * 484319251c5SThomas Zimmermann * We only complain about errors here, no action is taken as the most likely 485319251c5SThomas Zimmermann * error can only happen due to a mismatch between the bootloader which set 486319251c5SThomas Zimmermann * up the "simple-framebuffer" dt node, and the PM domain providers in the 487319251c5SThomas Zimmermann * device tree. Chances are that there are no adverse effects, and if there are, 488319251c5SThomas Zimmermann * a clean teardown of the fb probe will not help us much either. So just 489319251c5SThomas Zimmermann * complain and carry on, and hope that the user actually gets a working fb at 490319251c5SThomas Zimmermann * the end of things. 491319251c5SThomas Zimmermann */ 492319251c5SThomas Zimmermann static void simpledrm_device_detach_genpd(void *res) 493319251c5SThomas Zimmermann { 494319251c5SThomas Zimmermann int i; 495319251c5SThomas Zimmermann struct simpledrm_device *sdev = res; 496319251c5SThomas Zimmermann 497319251c5SThomas Zimmermann if (sdev->pwr_dom_count <= 1) 498319251c5SThomas Zimmermann return; 499319251c5SThomas Zimmermann 500319251c5SThomas Zimmermann for (i = sdev->pwr_dom_count - 1; i >= 0; i--) { 501319251c5SThomas Zimmermann if (sdev->pwr_dom_links[i]) 502319251c5SThomas Zimmermann device_link_del(sdev->pwr_dom_links[i]); 503319251c5SThomas Zimmermann if (!IS_ERR_OR_NULL(sdev->pwr_dom_devs[i])) 504319251c5SThomas Zimmermann dev_pm_domain_detach(sdev->pwr_dom_devs[i], true); 505319251c5SThomas Zimmermann } 506319251c5SThomas Zimmermann } 507319251c5SThomas Zimmermann 508319251c5SThomas Zimmermann static int simpledrm_device_attach_genpd(struct simpledrm_device *sdev) 509319251c5SThomas Zimmermann { 510b5626f6fSThomas Zimmermann struct device *dev = sdev->sysfb.dev.dev; 511319251c5SThomas Zimmermann int i; 512319251c5SThomas Zimmermann 513319251c5SThomas Zimmermann sdev->pwr_dom_count = of_count_phandle_with_args(dev->of_node, "power-domains", 514319251c5SThomas Zimmermann "#power-domain-cells"); 515319251c5SThomas Zimmermann /* 516319251c5SThomas Zimmermann * Single power-domain devices are handled by driver core nothing to do 517319251c5SThomas Zimmermann * here. The same for device nodes without "power-domains" property. 518319251c5SThomas Zimmermann */ 519319251c5SThomas Zimmermann if (sdev->pwr_dom_count <= 1) 520319251c5SThomas Zimmermann return 0; 521319251c5SThomas Zimmermann 522319251c5SThomas Zimmermann sdev->pwr_dom_devs = devm_kcalloc(dev, sdev->pwr_dom_count, 523319251c5SThomas Zimmermann sizeof(*sdev->pwr_dom_devs), 524319251c5SThomas Zimmermann GFP_KERNEL); 525319251c5SThomas Zimmermann if (!sdev->pwr_dom_devs) 526319251c5SThomas Zimmermann return -ENOMEM; 527319251c5SThomas Zimmermann 528319251c5SThomas Zimmermann sdev->pwr_dom_links = devm_kcalloc(dev, sdev->pwr_dom_count, 529319251c5SThomas Zimmermann sizeof(*sdev->pwr_dom_links), 530319251c5SThomas Zimmermann GFP_KERNEL); 531319251c5SThomas Zimmermann if (!sdev->pwr_dom_links) 532319251c5SThomas Zimmermann return -ENOMEM; 533319251c5SThomas Zimmermann 534319251c5SThomas Zimmermann for (i = 0; i < sdev->pwr_dom_count; i++) { 535319251c5SThomas Zimmermann sdev->pwr_dom_devs[i] = dev_pm_domain_attach_by_id(dev, i); 536319251c5SThomas Zimmermann if (IS_ERR(sdev->pwr_dom_devs[i])) { 537319251c5SThomas Zimmermann int ret = PTR_ERR(sdev->pwr_dom_devs[i]); 538319251c5SThomas Zimmermann if (ret == -EPROBE_DEFER) { 539319251c5SThomas Zimmermann simpledrm_device_detach_genpd(sdev); 540319251c5SThomas Zimmermann return ret; 541319251c5SThomas Zimmermann } 542b5626f6fSThomas Zimmermann drm_warn(&sdev->sysfb.dev, 543319251c5SThomas Zimmermann "pm_domain_attach_by_id(%u) failed: %d\n", i, ret); 544319251c5SThomas Zimmermann continue; 545319251c5SThomas Zimmermann } 546319251c5SThomas Zimmermann 547319251c5SThomas Zimmermann sdev->pwr_dom_links[i] = device_link_add(dev, 548319251c5SThomas Zimmermann sdev->pwr_dom_devs[i], 549319251c5SThomas Zimmermann DL_FLAG_STATELESS | 550319251c5SThomas Zimmermann DL_FLAG_PM_RUNTIME | 551319251c5SThomas Zimmermann DL_FLAG_RPM_ACTIVE); 552319251c5SThomas Zimmermann if (!sdev->pwr_dom_links[i]) 553b5626f6fSThomas Zimmermann drm_warn(&sdev->sysfb.dev, "failed to link power-domain %d\n", i); 554319251c5SThomas Zimmermann } 555319251c5SThomas Zimmermann 556319251c5SThomas Zimmermann return devm_add_action_or_reset(dev, simpledrm_device_detach_genpd, sdev); 557319251c5SThomas Zimmermann } 558319251c5SThomas Zimmermann #else 559319251c5SThomas Zimmermann static int simpledrm_device_attach_genpd(struct simpledrm_device *sdev) 560319251c5SThomas Zimmermann { 561319251c5SThomas Zimmermann return 0; 562319251c5SThomas Zimmermann } 563319251c5SThomas Zimmermann #endif 564319251c5SThomas Zimmermann 565319251c5SThomas Zimmermann /* 566319251c5SThomas Zimmermann * Modesetting 567319251c5SThomas Zimmermann */ 568319251c5SThomas Zimmermann 569*177dfbdbSThomas Zimmermann static const u64 simpledrm_primary_plane_format_modifiers[] = { 570*177dfbdbSThomas Zimmermann DRM_SYSFB_PLANE_FORMAT_MODIFIERS, 571319251c5SThomas Zimmermann }; 572319251c5SThomas Zimmermann 573319251c5SThomas Zimmermann static const struct drm_plane_helper_funcs simpledrm_primary_plane_helper_funcs = { 574*177dfbdbSThomas Zimmermann DRM_SYSFB_PLANE_HELPER_FUNCS, 575319251c5SThomas Zimmermann }; 576319251c5SThomas Zimmermann 577319251c5SThomas Zimmermann static const struct drm_plane_funcs simpledrm_primary_plane_funcs = { 578*177dfbdbSThomas Zimmermann DRM_SYSFB_PLANE_FUNCS, 579319251c5SThomas Zimmermann .destroy = drm_plane_cleanup, 580319251c5SThomas Zimmermann }; 581319251c5SThomas Zimmermann 582319251c5SThomas Zimmermann static const struct drm_crtc_helper_funcs simpledrm_crtc_helper_funcs = { 583ea86aba4SThomas Zimmermann DRM_SYSFB_CRTC_HELPER_FUNCS, 584319251c5SThomas Zimmermann }; 585319251c5SThomas Zimmermann 586319251c5SThomas Zimmermann static const struct drm_crtc_funcs simpledrm_crtc_funcs = { 58768ab3253SThomas Zimmermann DRM_SYSFB_CRTC_FUNCS, 588319251c5SThomas Zimmermann .destroy = drm_crtc_cleanup, 589319251c5SThomas Zimmermann }; 590319251c5SThomas Zimmermann 591319251c5SThomas Zimmermann static const struct drm_encoder_funcs simpledrm_encoder_funcs = { 592319251c5SThomas Zimmermann .destroy = drm_encoder_cleanup, 593319251c5SThomas Zimmermann }; 594319251c5SThomas Zimmermann 595319251c5SThomas Zimmermann static const struct drm_connector_helper_funcs simpledrm_connector_helper_funcs = { 59601e48e52SThomas Zimmermann DRM_SYSFB_CONNECTOR_HELPER_FUNCS, 597319251c5SThomas Zimmermann }; 598319251c5SThomas Zimmermann 599319251c5SThomas Zimmermann static const struct drm_connector_funcs simpledrm_connector_funcs = { 60001e48e52SThomas Zimmermann DRM_SYSFB_CONNECTOR_FUNCS, 601319251c5SThomas Zimmermann .destroy = drm_connector_cleanup, 602319251c5SThomas Zimmermann }; 603319251c5SThomas Zimmermann 604319251c5SThomas Zimmermann static const struct drm_mode_config_funcs simpledrm_mode_config_funcs = { 605559d105fSThomas Zimmermann DRM_SYSFB_MODE_CONFIG_FUNCS, 606319251c5SThomas Zimmermann }; 607319251c5SThomas Zimmermann 608319251c5SThomas Zimmermann /* 609319251c5SThomas Zimmermann * Init / Cleanup 610319251c5SThomas Zimmermann */ 611319251c5SThomas Zimmermann 612319251c5SThomas Zimmermann static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv, 613319251c5SThomas Zimmermann struct platform_device *pdev) 614319251c5SThomas Zimmermann { 615319251c5SThomas Zimmermann const struct simplefb_platform_data *pd = dev_get_platdata(&pdev->dev); 616319251c5SThomas Zimmermann struct device_node *of_node = pdev->dev.of_node; 617319251c5SThomas Zimmermann struct simpledrm_device *sdev; 618b5626f6fSThomas Zimmermann struct drm_sysfb_device *sysfb; 619319251c5SThomas Zimmermann struct drm_device *dev; 620319251c5SThomas Zimmermann int width, height, stride; 621319251c5SThomas Zimmermann int width_mm = 0, height_mm = 0; 622319251c5SThomas Zimmermann struct device_node *panel_node; 623319251c5SThomas Zimmermann const struct drm_format_info *format; 624319251c5SThomas Zimmermann struct resource *res, *mem = NULL; 625319251c5SThomas Zimmermann struct drm_plane *primary_plane; 626319251c5SThomas Zimmermann struct drm_crtc *crtc; 627319251c5SThomas Zimmermann struct drm_encoder *encoder; 628319251c5SThomas Zimmermann struct drm_connector *connector; 629319251c5SThomas Zimmermann unsigned long max_width, max_height; 630319251c5SThomas Zimmermann size_t nformats; 631319251c5SThomas Zimmermann int ret; 632319251c5SThomas Zimmermann 633b5626f6fSThomas Zimmermann sdev = devm_drm_dev_alloc(&pdev->dev, drv, struct simpledrm_device, sysfb.dev); 634319251c5SThomas Zimmermann if (IS_ERR(sdev)) 635319251c5SThomas Zimmermann return ERR_CAST(sdev); 636b5626f6fSThomas Zimmermann sysfb = &sdev->sysfb; 637b5626f6fSThomas Zimmermann dev = &sysfb->dev; 638319251c5SThomas Zimmermann platform_set_drvdata(pdev, sdev); 639319251c5SThomas Zimmermann 640319251c5SThomas Zimmermann /* 641319251c5SThomas Zimmermann * Hardware settings 642319251c5SThomas Zimmermann */ 643319251c5SThomas Zimmermann 644319251c5SThomas Zimmermann ret = simpledrm_device_init_clocks(sdev); 645319251c5SThomas Zimmermann if (ret) 646319251c5SThomas Zimmermann return ERR_PTR(ret); 647319251c5SThomas Zimmermann ret = simpledrm_device_init_regulators(sdev); 648319251c5SThomas Zimmermann if (ret) 649319251c5SThomas Zimmermann return ERR_PTR(ret); 650319251c5SThomas Zimmermann ret = simpledrm_device_attach_genpd(sdev); 651319251c5SThomas Zimmermann if (ret) 652319251c5SThomas Zimmermann return ERR_PTR(ret); 653319251c5SThomas Zimmermann 654319251c5SThomas Zimmermann if (pd) { 655319251c5SThomas Zimmermann width = simplefb_get_width_pd(dev, pd); 656319251c5SThomas Zimmermann if (width < 0) 657319251c5SThomas Zimmermann return ERR_PTR(width); 658319251c5SThomas Zimmermann height = simplefb_get_height_pd(dev, pd); 659319251c5SThomas Zimmermann if (height < 0) 660319251c5SThomas Zimmermann return ERR_PTR(height); 661319251c5SThomas Zimmermann stride = simplefb_get_stride_pd(dev, pd); 662319251c5SThomas Zimmermann if (stride < 0) 663319251c5SThomas Zimmermann return ERR_PTR(stride); 664319251c5SThomas Zimmermann format = simplefb_get_format_pd(dev, pd); 665319251c5SThomas Zimmermann if (IS_ERR(format)) 666319251c5SThomas Zimmermann return ERR_CAST(format); 667319251c5SThomas Zimmermann } else if (of_node) { 668319251c5SThomas Zimmermann width = simplefb_get_width_of(dev, of_node); 669319251c5SThomas Zimmermann if (width < 0) 670319251c5SThomas Zimmermann return ERR_PTR(width); 671319251c5SThomas Zimmermann height = simplefb_get_height_of(dev, of_node); 672319251c5SThomas Zimmermann if (height < 0) 673319251c5SThomas Zimmermann return ERR_PTR(height); 674319251c5SThomas Zimmermann stride = simplefb_get_stride_of(dev, of_node); 675319251c5SThomas Zimmermann if (stride < 0) 676319251c5SThomas Zimmermann return ERR_PTR(stride); 677319251c5SThomas Zimmermann format = simplefb_get_format_of(dev, of_node); 678319251c5SThomas Zimmermann if (IS_ERR(format)) 679319251c5SThomas Zimmermann return ERR_CAST(format); 680319251c5SThomas Zimmermann mem = simplefb_get_memory_of(dev, of_node); 681319251c5SThomas Zimmermann if (IS_ERR(mem)) 682319251c5SThomas Zimmermann return ERR_CAST(mem); 683319251c5SThomas Zimmermann panel_node = of_parse_phandle(of_node, "panel", 0); 684319251c5SThomas Zimmermann if (panel_node) { 685319251c5SThomas Zimmermann simplefb_read_u32_of(dev, panel_node, "width-mm", &width_mm); 686319251c5SThomas Zimmermann simplefb_read_u32_of(dev, panel_node, "height-mm", &height_mm); 687319251c5SThomas Zimmermann of_node_put(panel_node); 688319251c5SThomas Zimmermann } 689319251c5SThomas Zimmermann } else { 690319251c5SThomas Zimmermann drm_err(dev, "no simplefb configuration found\n"); 691319251c5SThomas Zimmermann return ERR_PTR(-ENODEV); 692319251c5SThomas Zimmermann } 693319251c5SThomas Zimmermann if (!stride) { 694319251c5SThomas Zimmermann stride = drm_format_info_min_pitch(format, 0, width); 695319251c5SThomas Zimmermann if (drm_WARN_ON(dev, !stride)) 696319251c5SThomas Zimmermann return ERR_PTR(-EINVAL); 697319251c5SThomas Zimmermann } 698319251c5SThomas Zimmermann 699333376e9SThomas Zimmermann sysfb->fb_mode = drm_sysfb_mode(width, height, width_mm, height_mm); 700b5626f6fSThomas Zimmermann sysfb->fb_format = format; 701b5626f6fSThomas Zimmermann sysfb->fb_pitch = stride; 702319251c5SThomas Zimmermann 703b5626f6fSThomas Zimmermann drm_dbg(dev, "display mode={" DRM_MODE_FMT "}\n", DRM_MODE_ARG(&sysfb->fb_mode)); 704319251c5SThomas Zimmermann drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, stride=%d byte\n", 705319251c5SThomas Zimmermann &format->format, width, height, stride); 706319251c5SThomas Zimmermann 707319251c5SThomas Zimmermann /* 708319251c5SThomas Zimmermann * Memory management 709319251c5SThomas Zimmermann */ 710319251c5SThomas Zimmermann 711319251c5SThomas Zimmermann if (mem) { 712319251c5SThomas Zimmermann void *screen_base; 713319251c5SThomas Zimmermann 714319251c5SThomas Zimmermann ret = devm_aperture_acquire_for_platform_device(pdev, mem->start, 715319251c5SThomas Zimmermann resource_size(mem)); 716319251c5SThomas Zimmermann if (ret) { 717319251c5SThomas Zimmermann drm_err(dev, "could not acquire memory range %pr: %d\n", mem, ret); 718319251c5SThomas Zimmermann return ERR_PTR(ret); 719319251c5SThomas Zimmermann } 720319251c5SThomas Zimmermann 721319251c5SThomas Zimmermann drm_dbg(dev, "using system memory framebuffer at %pr\n", mem); 722319251c5SThomas Zimmermann 723319251c5SThomas Zimmermann screen_base = devm_memremap(dev->dev, mem->start, resource_size(mem), MEMREMAP_WC); 724319251c5SThomas Zimmermann if (IS_ERR(screen_base)) 725319251c5SThomas Zimmermann return screen_base; 726319251c5SThomas Zimmermann 727b5626f6fSThomas Zimmermann iosys_map_set_vaddr(&sysfb->fb_addr, screen_base); 728319251c5SThomas Zimmermann } else { 729319251c5SThomas Zimmermann void __iomem *screen_base; 730319251c5SThomas Zimmermann 731319251c5SThomas Zimmermann res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 732319251c5SThomas Zimmermann if (!res) 733319251c5SThomas Zimmermann return ERR_PTR(-EINVAL); 734319251c5SThomas Zimmermann 735319251c5SThomas Zimmermann ret = devm_aperture_acquire_for_platform_device(pdev, res->start, 736319251c5SThomas Zimmermann resource_size(res)); 737319251c5SThomas Zimmermann if (ret) { 738319251c5SThomas Zimmermann drm_err(dev, "could not acquire memory range %pr: %d\n", res, ret); 739319251c5SThomas Zimmermann return ERR_PTR(ret); 740319251c5SThomas Zimmermann } 741319251c5SThomas Zimmermann 742319251c5SThomas Zimmermann drm_dbg(dev, "using I/O memory framebuffer at %pr\n", res); 743319251c5SThomas Zimmermann 744319251c5SThomas Zimmermann mem = devm_request_mem_region(&pdev->dev, res->start, resource_size(res), 745319251c5SThomas Zimmermann drv->name); 746319251c5SThomas Zimmermann if (!mem) { 747319251c5SThomas Zimmermann /* 748319251c5SThomas Zimmermann * We cannot make this fatal. Sometimes this comes from magic 749319251c5SThomas Zimmermann * spaces our resource handlers simply don't know about. Use 750319251c5SThomas Zimmermann * the I/O-memory resource as-is and try to map that instead. 751319251c5SThomas Zimmermann */ 752319251c5SThomas Zimmermann drm_warn(dev, "could not acquire memory region %pr\n", res); 753319251c5SThomas Zimmermann mem = res; 754319251c5SThomas Zimmermann } 755319251c5SThomas Zimmermann 756319251c5SThomas Zimmermann screen_base = devm_ioremap_wc(&pdev->dev, mem->start, resource_size(mem)); 757319251c5SThomas Zimmermann if (!screen_base) 758319251c5SThomas Zimmermann return ERR_PTR(-ENOMEM); 759319251c5SThomas Zimmermann 760b5626f6fSThomas Zimmermann iosys_map_set_vaddr_iomem(&sysfb->fb_addr, screen_base); 761319251c5SThomas Zimmermann } 762319251c5SThomas Zimmermann 763319251c5SThomas Zimmermann /* 764319251c5SThomas Zimmermann * Modesetting 765319251c5SThomas Zimmermann */ 766319251c5SThomas Zimmermann 767319251c5SThomas Zimmermann ret = drmm_mode_config_init(dev); 768319251c5SThomas Zimmermann if (ret) 769319251c5SThomas Zimmermann return ERR_PTR(ret); 770319251c5SThomas Zimmermann 771319251c5SThomas Zimmermann max_width = max_t(unsigned long, width, DRM_SHADOW_PLANE_MAX_WIDTH); 772319251c5SThomas Zimmermann max_height = max_t(unsigned long, height, DRM_SHADOW_PLANE_MAX_HEIGHT); 773319251c5SThomas Zimmermann 774319251c5SThomas Zimmermann dev->mode_config.min_width = width; 775319251c5SThomas Zimmermann dev->mode_config.max_width = max_width; 776319251c5SThomas Zimmermann dev->mode_config.min_height = height; 777319251c5SThomas Zimmermann dev->mode_config.max_height = max_height; 778319251c5SThomas Zimmermann dev->mode_config.preferred_depth = format->depth; 779319251c5SThomas Zimmermann dev->mode_config.funcs = &simpledrm_mode_config_funcs; 780319251c5SThomas Zimmermann 781319251c5SThomas Zimmermann /* Primary plane */ 782319251c5SThomas Zimmermann 783319251c5SThomas Zimmermann nformats = drm_fb_build_fourcc_list(dev, &format->format, 1, 784319251c5SThomas Zimmermann sdev->formats, ARRAY_SIZE(sdev->formats)); 785319251c5SThomas Zimmermann 786319251c5SThomas Zimmermann primary_plane = &sdev->primary_plane; 787319251c5SThomas Zimmermann ret = drm_universal_plane_init(dev, primary_plane, 0, &simpledrm_primary_plane_funcs, 788319251c5SThomas Zimmermann sdev->formats, nformats, 789319251c5SThomas Zimmermann simpledrm_primary_plane_format_modifiers, 790319251c5SThomas Zimmermann DRM_PLANE_TYPE_PRIMARY, NULL); 791319251c5SThomas Zimmermann if (ret) 792319251c5SThomas Zimmermann return ERR_PTR(ret); 793319251c5SThomas Zimmermann drm_plane_helper_add(primary_plane, &simpledrm_primary_plane_helper_funcs); 794319251c5SThomas Zimmermann drm_plane_enable_fb_damage_clips(primary_plane); 795319251c5SThomas Zimmermann 796319251c5SThomas Zimmermann /* CRTC */ 797319251c5SThomas Zimmermann 798319251c5SThomas Zimmermann crtc = &sdev->crtc; 799319251c5SThomas Zimmermann ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, 800319251c5SThomas Zimmermann &simpledrm_crtc_funcs, NULL); 801319251c5SThomas Zimmermann if (ret) 802319251c5SThomas Zimmermann return ERR_PTR(ret); 803319251c5SThomas Zimmermann drm_crtc_helper_add(crtc, &simpledrm_crtc_helper_funcs); 804319251c5SThomas Zimmermann 805319251c5SThomas Zimmermann /* Encoder */ 806319251c5SThomas Zimmermann 807319251c5SThomas Zimmermann encoder = &sdev->encoder; 808319251c5SThomas Zimmermann ret = drm_encoder_init(dev, encoder, &simpledrm_encoder_funcs, 809319251c5SThomas Zimmermann DRM_MODE_ENCODER_NONE, NULL); 810319251c5SThomas Zimmermann if (ret) 811319251c5SThomas Zimmermann return ERR_PTR(ret); 812319251c5SThomas Zimmermann encoder->possible_crtcs = drm_crtc_mask(crtc); 813319251c5SThomas Zimmermann 814319251c5SThomas Zimmermann /* Connector */ 815319251c5SThomas Zimmermann 816319251c5SThomas Zimmermann connector = &sdev->connector; 817319251c5SThomas Zimmermann ret = drm_connector_init(dev, connector, &simpledrm_connector_funcs, 818319251c5SThomas Zimmermann DRM_MODE_CONNECTOR_Unknown); 819319251c5SThomas Zimmermann if (ret) 820319251c5SThomas Zimmermann return ERR_PTR(ret); 821319251c5SThomas Zimmermann drm_connector_helper_add(connector, &simpledrm_connector_helper_funcs); 822319251c5SThomas Zimmermann drm_connector_set_panel_orientation_with_quirk(connector, 823319251c5SThomas Zimmermann DRM_MODE_PANEL_ORIENTATION_UNKNOWN, 824319251c5SThomas Zimmermann width, height); 825319251c5SThomas Zimmermann 826319251c5SThomas Zimmermann ret = drm_connector_attach_encoder(connector, encoder); 827319251c5SThomas Zimmermann if (ret) 828319251c5SThomas Zimmermann return ERR_PTR(ret); 829319251c5SThomas Zimmermann 830319251c5SThomas Zimmermann drm_mode_config_reset(dev); 831319251c5SThomas Zimmermann 832319251c5SThomas Zimmermann return sdev; 833319251c5SThomas Zimmermann } 834319251c5SThomas Zimmermann 835319251c5SThomas Zimmermann /* 836319251c5SThomas Zimmermann * DRM driver 837319251c5SThomas Zimmermann */ 838319251c5SThomas Zimmermann 839319251c5SThomas Zimmermann DEFINE_DRM_GEM_FOPS(simpledrm_fops); 840319251c5SThomas Zimmermann 841319251c5SThomas Zimmermann static struct drm_driver simpledrm_driver = { 842319251c5SThomas Zimmermann DRM_GEM_SHMEM_DRIVER_OPS, 843319251c5SThomas Zimmermann DRM_FBDEV_SHMEM_DRIVER_OPS, 844319251c5SThomas Zimmermann .name = DRIVER_NAME, 845319251c5SThomas Zimmermann .desc = DRIVER_DESC, 846319251c5SThomas Zimmermann .major = DRIVER_MAJOR, 847319251c5SThomas Zimmermann .minor = DRIVER_MINOR, 848319251c5SThomas Zimmermann .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET, 849319251c5SThomas Zimmermann .fops = &simpledrm_fops, 850319251c5SThomas Zimmermann }; 851319251c5SThomas Zimmermann 852319251c5SThomas Zimmermann /* 853319251c5SThomas Zimmermann * Platform driver 854319251c5SThomas Zimmermann */ 855319251c5SThomas Zimmermann 856319251c5SThomas Zimmermann static int simpledrm_probe(struct platform_device *pdev) 857319251c5SThomas Zimmermann { 858319251c5SThomas Zimmermann struct simpledrm_device *sdev; 859b5626f6fSThomas Zimmermann struct drm_sysfb_device *sysfb; 860319251c5SThomas Zimmermann struct drm_device *dev; 861319251c5SThomas Zimmermann int ret; 862319251c5SThomas Zimmermann 863319251c5SThomas Zimmermann sdev = simpledrm_device_create(&simpledrm_driver, pdev); 864319251c5SThomas Zimmermann if (IS_ERR(sdev)) 865319251c5SThomas Zimmermann return PTR_ERR(sdev); 866b5626f6fSThomas Zimmermann sysfb = &sdev->sysfb; 867b5626f6fSThomas Zimmermann dev = &sysfb->dev; 868319251c5SThomas Zimmermann 869319251c5SThomas Zimmermann ret = drm_dev_register(dev, 0); 870319251c5SThomas Zimmermann if (ret) 871319251c5SThomas Zimmermann return ret; 872319251c5SThomas Zimmermann 873b5626f6fSThomas Zimmermann drm_client_setup(dev, sdev->sysfb.fb_format); 874319251c5SThomas Zimmermann 875319251c5SThomas Zimmermann return 0; 876319251c5SThomas Zimmermann } 877319251c5SThomas Zimmermann 878319251c5SThomas Zimmermann static void simpledrm_remove(struct platform_device *pdev) 879319251c5SThomas Zimmermann { 880319251c5SThomas Zimmermann struct simpledrm_device *sdev = platform_get_drvdata(pdev); 881b5626f6fSThomas Zimmermann struct drm_device *dev = &sdev->sysfb.dev; 882319251c5SThomas Zimmermann 883319251c5SThomas Zimmermann drm_dev_unplug(dev); 884319251c5SThomas Zimmermann } 885319251c5SThomas Zimmermann 886319251c5SThomas Zimmermann static const struct of_device_id simpledrm_of_match_table[] = { 887319251c5SThomas Zimmermann { .compatible = "simple-framebuffer", }, 888319251c5SThomas Zimmermann { }, 889319251c5SThomas Zimmermann }; 890319251c5SThomas Zimmermann MODULE_DEVICE_TABLE(of, simpledrm_of_match_table); 891319251c5SThomas Zimmermann 892319251c5SThomas Zimmermann static struct platform_driver simpledrm_platform_driver = { 893319251c5SThomas Zimmermann .driver = { 894319251c5SThomas Zimmermann .name = "simple-framebuffer", /* connect to sysfb */ 895319251c5SThomas Zimmermann .of_match_table = simpledrm_of_match_table, 896319251c5SThomas Zimmermann }, 897319251c5SThomas Zimmermann .probe = simpledrm_probe, 898319251c5SThomas Zimmermann .remove = simpledrm_remove, 899319251c5SThomas Zimmermann }; 900319251c5SThomas Zimmermann 901319251c5SThomas Zimmermann module_platform_driver(simpledrm_platform_driver); 902319251c5SThomas Zimmermann 903319251c5SThomas Zimmermann MODULE_DESCRIPTION(DRIVER_DESC); 904319251c5SThomas Zimmermann MODULE_LICENSE("GPL v2"); 905