1c8a17756SThomas Zimmermann // SPDX-License-Identifier: GPL-2.0-only 2c8a17756SThomas Zimmermann 3c8a17756SThomas Zimmermann #include <linux/of_address.h> 4c8a17756SThomas Zimmermann #include <linux/pci.h> 5c8a17756SThomas Zimmermann #include <linux/platform_device.h> 6c8a17756SThomas Zimmermann 7c8a17756SThomas Zimmermann #include <drm/drm_aperture.h> 8c8a17756SThomas Zimmermann #include <drm/drm_atomic.h> 9c8a17756SThomas Zimmermann #include <drm/drm_atomic_state_helper.h> 10c8a17756SThomas Zimmermann #include <drm/drm_connector.h> 11c8a17756SThomas Zimmermann #include <drm/drm_damage_helper.h> 12c8a17756SThomas Zimmermann #include <drm/drm_device.h> 13c8a17756SThomas Zimmermann #include <drm/drm_drv.h> 14c8a17756SThomas Zimmermann #include <drm/drm_fb_helper.h> 15c8a17756SThomas Zimmermann #include <drm/drm_format_helper.h> 16c8a17756SThomas Zimmermann #include <drm/drm_gem_atomic_helper.h> 17c8a17756SThomas Zimmermann #include <drm/drm_gem_framebuffer_helper.h> 18c8a17756SThomas Zimmermann #include <drm/drm_gem_shmem_helper.h> 19c8a17756SThomas Zimmermann #include <drm/drm_managed.h> 20c8a17756SThomas Zimmermann #include <drm/drm_modeset_helper_vtables.h> 21c8a17756SThomas Zimmermann #include <drm/drm_plane_helper.h> 22c8a17756SThomas Zimmermann #include <drm/drm_probe_helper.h> 23c8a17756SThomas Zimmermann #include <drm/drm_simple_kms_helper.h> 24c8a17756SThomas Zimmermann 25c8a17756SThomas Zimmermann #define DRIVER_NAME "ofdrm" 26c8a17756SThomas Zimmermann #define DRIVER_DESC "DRM driver for OF platform devices" 27c8a17756SThomas Zimmermann #define DRIVER_DATE "20220501" 28c8a17756SThomas Zimmermann #define DRIVER_MAJOR 1 29c8a17756SThomas Zimmermann #define DRIVER_MINOR 0 30c8a17756SThomas Zimmermann 31c8a17756SThomas Zimmermann /* 32c8a17756SThomas Zimmermann * Helpers for display nodes 33c8a17756SThomas Zimmermann */ 34c8a17756SThomas Zimmermann 35c8a17756SThomas Zimmermann static int display_get_validated_int(struct drm_device *dev, const char *name, uint32_t value) 36c8a17756SThomas Zimmermann { 37c8a17756SThomas Zimmermann if (value > INT_MAX) { 38c8a17756SThomas Zimmermann drm_err(dev, "invalid framebuffer %s of %u\n", name, value); 39c8a17756SThomas Zimmermann return -EINVAL; 40c8a17756SThomas Zimmermann } 41c8a17756SThomas Zimmermann return (int)value; 42c8a17756SThomas Zimmermann } 43c8a17756SThomas Zimmermann 44c8a17756SThomas Zimmermann static int display_get_validated_int0(struct drm_device *dev, const char *name, uint32_t value) 45c8a17756SThomas Zimmermann { 46c8a17756SThomas Zimmermann if (!value) { 47c8a17756SThomas Zimmermann drm_err(dev, "invalid framebuffer %s of %u\n", name, value); 48c8a17756SThomas Zimmermann return -EINVAL; 49c8a17756SThomas Zimmermann } 50c8a17756SThomas Zimmermann return display_get_validated_int(dev, name, value); 51c8a17756SThomas Zimmermann } 52c8a17756SThomas Zimmermann 53c8a17756SThomas Zimmermann static const struct drm_format_info *display_get_validated_format(struct drm_device *dev, 54c8a17756SThomas Zimmermann u32 depth) 55c8a17756SThomas Zimmermann { 56c8a17756SThomas Zimmermann const struct drm_format_info *info; 57c8a17756SThomas Zimmermann u32 format; 58c8a17756SThomas Zimmermann 59c8a17756SThomas Zimmermann switch (depth) { 60c8a17756SThomas Zimmermann case 8: 61c8a17756SThomas Zimmermann format = drm_mode_legacy_fb_format(8, 8); 62c8a17756SThomas Zimmermann break; 63c8a17756SThomas Zimmermann case 15: 64c8a17756SThomas Zimmermann case 16: 65c8a17756SThomas Zimmermann format = drm_mode_legacy_fb_format(16, depth); 66c8a17756SThomas Zimmermann break; 67c8a17756SThomas Zimmermann case 32: 68c8a17756SThomas Zimmermann format = drm_mode_legacy_fb_format(32, 24); 69c8a17756SThomas Zimmermann break; 70c8a17756SThomas Zimmermann default: 71c8a17756SThomas Zimmermann drm_err(dev, "unsupported framebuffer depth %u\n", depth); 72c8a17756SThomas Zimmermann return ERR_PTR(-EINVAL); 73c8a17756SThomas Zimmermann } 74c8a17756SThomas Zimmermann 75c8a17756SThomas Zimmermann info = drm_format_info(format); 76c8a17756SThomas Zimmermann if (!info) { 77c8a17756SThomas Zimmermann drm_err(dev, "cannot find framebuffer format for depth %u\n", depth); 78c8a17756SThomas Zimmermann return ERR_PTR(-EINVAL); 79c8a17756SThomas Zimmermann } 80c8a17756SThomas Zimmermann 81c8a17756SThomas Zimmermann return info; 82c8a17756SThomas Zimmermann } 83c8a17756SThomas Zimmermann 84c8a17756SThomas Zimmermann static int display_read_u32_of(struct drm_device *dev, struct device_node *of_node, 85c8a17756SThomas Zimmermann const char *name, u32 *value) 86c8a17756SThomas Zimmermann { 87c8a17756SThomas Zimmermann int ret = of_property_read_u32(of_node, name, value); 88c8a17756SThomas Zimmermann 89c8a17756SThomas Zimmermann if (ret) 90c8a17756SThomas Zimmermann drm_err(dev, "cannot parse framebuffer %s: error %d\n", name, ret); 91c8a17756SThomas Zimmermann return ret; 92c8a17756SThomas Zimmermann } 93c8a17756SThomas Zimmermann 94c8a17756SThomas Zimmermann static int display_get_width_of(struct drm_device *dev, struct device_node *of_node) 95c8a17756SThomas Zimmermann { 96c8a17756SThomas Zimmermann u32 width; 97c8a17756SThomas Zimmermann int ret = display_read_u32_of(dev, of_node, "width", &width); 98c8a17756SThomas Zimmermann 99c8a17756SThomas Zimmermann if (ret) 100c8a17756SThomas Zimmermann return ret; 101c8a17756SThomas Zimmermann return display_get_validated_int0(dev, "width", width); 102c8a17756SThomas Zimmermann } 103c8a17756SThomas Zimmermann 104c8a17756SThomas Zimmermann static int display_get_height_of(struct drm_device *dev, struct device_node *of_node) 105c8a17756SThomas Zimmermann { 106c8a17756SThomas Zimmermann u32 height; 107c8a17756SThomas Zimmermann int ret = display_read_u32_of(dev, of_node, "height", &height); 108c8a17756SThomas Zimmermann 109c8a17756SThomas Zimmermann if (ret) 110c8a17756SThomas Zimmermann return ret; 111c8a17756SThomas Zimmermann return display_get_validated_int0(dev, "height", height); 112c8a17756SThomas Zimmermann } 113c8a17756SThomas Zimmermann 114c8a17756SThomas Zimmermann static int display_get_depth_of(struct drm_device *dev, struct device_node *of_node) 115c8a17756SThomas Zimmermann { 116c8a17756SThomas Zimmermann u32 depth; 117c8a17756SThomas Zimmermann int ret = display_read_u32_of(dev, of_node, "depth", &depth); 118c8a17756SThomas Zimmermann 119c8a17756SThomas Zimmermann if (ret) 120c8a17756SThomas Zimmermann return ret; 121c8a17756SThomas Zimmermann return display_get_validated_int0(dev, "depth", depth); 122c8a17756SThomas Zimmermann } 123c8a17756SThomas Zimmermann 124c8a17756SThomas Zimmermann static int display_get_linebytes_of(struct drm_device *dev, struct device_node *of_node) 125c8a17756SThomas Zimmermann { 126c8a17756SThomas Zimmermann u32 linebytes; 127c8a17756SThomas Zimmermann int ret = display_read_u32_of(dev, of_node, "linebytes", &linebytes); 128c8a17756SThomas Zimmermann 129c8a17756SThomas Zimmermann if (ret) 130c8a17756SThomas Zimmermann return ret; 131c8a17756SThomas Zimmermann return display_get_validated_int(dev, "linebytes", linebytes); 132c8a17756SThomas Zimmermann } 133c8a17756SThomas Zimmermann 134c8a17756SThomas Zimmermann static u64 display_get_address_of(struct drm_device *dev, struct device_node *of_node) 135c8a17756SThomas Zimmermann { 136c8a17756SThomas Zimmermann u32 address; 137c8a17756SThomas Zimmermann int ret; 138c8a17756SThomas Zimmermann 139c8a17756SThomas Zimmermann /* 140c8a17756SThomas Zimmermann * Not all devices provide an address property, it's not 141c8a17756SThomas Zimmermann * a bug if this fails. The driver will try to find the 142c8a17756SThomas Zimmermann * framebuffer base address from the device's memory regions. 143c8a17756SThomas Zimmermann */ 144c8a17756SThomas Zimmermann ret = of_property_read_u32(of_node, "address", &address); 145c8a17756SThomas Zimmermann if (ret) 146c8a17756SThomas Zimmermann return OF_BAD_ADDR; 147c8a17756SThomas Zimmermann 148c8a17756SThomas Zimmermann return address; 149c8a17756SThomas Zimmermann } 150c8a17756SThomas Zimmermann 151c8a17756SThomas Zimmermann /* 152c8a17756SThomas Zimmermann * Open Firmware display device 153c8a17756SThomas Zimmermann */ 154c8a17756SThomas Zimmermann 155c8a17756SThomas Zimmermann struct ofdrm_device { 156c8a17756SThomas Zimmermann struct drm_device dev; 157c8a17756SThomas Zimmermann struct platform_device *pdev; 158c8a17756SThomas Zimmermann 159c8a17756SThomas Zimmermann /* firmware-buffer settings */ 160c8a17756SThomas Zimmermann struct iosys_map screen_base; 161c8a17756SThomas Zimmermann struct drm_display_mode mode; 162c8a17756SThomas Zimmermann const struct drm_format_info *format; 163c8a17756SThomas Zimmermann unsigned int pitch; 164c8a17756SThomas Zimmermann 165c8a17756SThomas Zimmermann /* modesetting */ 166c8a17756SThomas Zimmermann uint32_t formats[8]; 167c8a17756SThomas Zimmermann struct drm_plane primary_plane; 168c8a17756SThomas Zimmermann struct drm_crtc crtc; 169c8a17756SThomas Zimmermann struct drm_encoder encoder; 170c8a17756SThomas Zimmermann struct drm_connector connector; 171c8a17756SThomas Zimmermann }; 172c8a17756SThomas Zimmermann 173c8a17756SThomas Zimmermann static struct ofdrm_device *ofdrm_device_of_dev(struct drm_device *dev) 174c8a17756SThomas Zimmermann { 175c8a17756SThomas Zimmermann return container_of(dev, struct ofdrm_device, dev); 176c8a17756SThomas Zimmermann } 177c8a17756SThomas Zimmermann 178c8a17756SThomas Zimmermann /* 179c8a17756SThomas Zimmermann * Hardware 180c8a17756SThomas Zimmermann */ 181c8a17756SThomas Zimmermann 182c8a17756SThomas Zimmermann #if defined(CONFIG_PCI) 183c8a17756SThomas Zimmermann static struct pci_dev *display_get_pci_dev_of(struct drm_device *dev, struct device_node *of_node) 184c8a17756SThomas Zimmermann { 185c8a17756SThomas Zimmermann const __be32 *vendor_p, *device_p; 186c8a17756SThomas Zimmermann u32 vendor, device; 187c8a17756SThomas Zimmermann struct pci_dev *pcidev; 188c8a17756SThomas Zimmermann 189c8a17756SThomas Zimmermann vendor_p = of_get_property(of_node, "vendor-id", NULL); 190c8a17756SThomas Zimmermann if (!vendor_p) 191c8a17756SThomas Zimmermann return ERR_PTR(-ENODEV); 192c8a17756SThomas Zimmermann vendor = be32_to_cpup(vendor_p); 193c8a17756SThomas Zimmermann 194c8a17756SThomas Zimmermann device_p = of_get_property(of_node, "device-id", NULL); 195c8a17756SThomas Zimmermann if (!device_p) 196c8a17756SThomas Zimmermann return ERR_PTR(-ENODEV); 197c8a17756SThomas Zimmermann device = be32_to_cpup(device_p); 198c8a17756SThomas Zimmermann 199c8a17756SThomas Zimmermann pcidev = pci_get_device(vendor, device, NULL); 200c8a17756SThomas Zimmermann if (!pcidev) 201c8a17756SThomas Zimmermann return ERR_PTR(-ENODEV); 202c8a17756SThomas Zimmermann 203c8a17756SThomas Zimmermann return pcidev; 204c8a17756SThomas Zimmermann } 205c8a17756SThomas Zimmermann 206c8a17756SThomas Zimmermann static void ofdrm_pci_release(void *data) 207c8a17756SThomas Zimmermann { 208c8a17756SThomas Zimmermann struct pci_dev *pcidev = data; 209c8a17756SThomas Zimmermann 210c8a17756SThomas Zimmermann pci_disable_device(pcidev); 211c8a17756SThomas Zimmermann } 212c8a17756SThomas Zimmermann 213c8a17756SThomas Zimmermann static int ofdrm_device_init_pci(struct ofdrm_device *odev) 214c8a17756SThomas Zimmermann { 215c8a17756SThomas Zimmermann struct drm_device *dev = &odev->dev; 216c8a17756SThomas Zimmermann struct platform_device *pdev = to_platform_device(dev->dev); 217c8a17756SThomas Zimmermann struct device_node *of_node = pdev->dev.of_node; 218c8a17756SThomas Zimmermann struct pci_dev *pcidev; 219c8a17756SThomas Zimmermann int ret; 220c8a17756SThomas Zimmermann 221c8a17756SThomas Zimmermann /* 222c8a17756SThomas Zimmermann * Never use pcim_ or other managed helpers on the returned PCI 223c8a17756SThomas Zimmermann * device. Otherwise, probing the native driver will fail for 224c8a17756SThomas Zimmermann * resource conflicts. PCI-device management has to be tied to 225c8a17756SThomas Zimmermann * the lifetime of the platform device until the native driver 226c8a17756SThomas Zimmermann * takes over. 227c8a17756SThomas Zimmermann */ 228c8a17756SThomas Zimmermann pcidev = display_get_pci_dev_of(dev, of_node); 229c8a17756SThomas Zimmermann if (IS_ERR(pcidev)) 230c8a17756SThomas Zimmermann return 0; /* no PCI device found; ignore the error */ 231c8a17756SThomas Zimmermann 232c8a17756SThomas Zimmermann ret = pci_enable_device(pcidev); 233c8a17756SThomas Zimmermann if (ret) { 234c8a17756SThomas Zimmermann drm_err(dev, "pci_enable_device(%s) failed: %d\n", 235c8a17756SThomas Zimmermann dev_name(&pcidev->dev), ret); 236c8a17756SThomas Zimmermann return ret; 237c8a17756SThomas Zimmermann } 238c8a17756SThomas Zimmermann ret = devm_add_action_or_reset(&pdev->dev, ofdrm_pci_release, pcidev); 239c8a17756SThomas Zimmermann if (ret) 240c8a17756SThomas Zimmermann return ret; 241c8a17756SThomas Zimmermann 242c8a17756SThomas Zimmermann return 0; 243c8a17756SThomas Zimmermann } 244c8a17756SThomas Zimmermann #else 245c8a17756SThomas Zimmermann static int ofdrm_device_init_pci(struct ofdrm_device *odev) 246c8a17756SThomas Zimmermann { 247c8a17756SThomas Zimmermann return 0; 248c8a17756SThomas Zimmermann } 249c8a17756SThomas Zimmermann #endif 250c8a17756SThomas Zimmermann 251c8a17756SThomas Zimmermann /* 252c8a17756SThomas Zimmermann * OF display settings 253c8a17756SThomas Zimmermann */ 254c8a17756SThomas Zimmermann 255c8a17756SThomas Zimmermann static struct resource *ofdrm_find_fb_resource(struct ofdrm_device *odev, 256c8a17756SThomas Zimmermann struct resource *fb_res) 257c8a17756SThomas Zimmermann { 258c8a17756SThomas Zimmermann struct platform_device *pdev = to_platform_device(odev->dev.dev); 259c8a17756SThomas Zimmermann struct resource *res, *max_res = NULL; 260c8a17756SThomas Zimmermann u32 i; 261c8a17756SThomas Zimmermann 262c8a17756SThomas Zimmermann for (i = 0; pdev->num_resources; ++i) { 263c8a17756SThomas Zimmermann res = platform_get_resource(pdev, IORESOURCE_MEM, i); 264c8a17756SThomas Zimmermann if (!res) 265c8a17756SThomas Zimmermann break; /* all resources processed */ 266c8a17756SThomas Zimmermann if (resource_size(res) < resource_size(fb_res)) 267c8a17756SThomas Zimmermann continue; /* resource too small */ 268c8a17756SThomas Zimmermann if (fb_res->start && resource_contains(res, fb_res)) 269c8a17756SThomas Zimmermann return res; /* resource contains framebuffer */ 270c8a17756SThomas Zimmermann if (!max_res || resource_size(res) > resource_size(max_res)) 271c8a17756SThomas Zimmermann max_res = res; /* store largest resource as fallback */ 272c8a17756SThomas Zimmermann } 273c8a17756SThomas Zimmermann 274c8a17756SThomas Zimmermann return max_res; 275c8a17756SThomas Zimmermann } 276c8a17756SThomas Zimmermann 277c8a17756SThomas Zimmermann /* 278c8a17756SThomas Zimmermann * Modesetting 279c8a17756SThomas Zimmermann */ 280c8a17756SThomas Zimmermann 281*41137443SThomas Zimmermann struct ofdrm_crtc_state { 282*41137443SThomas Zimmermann struct drm_crtc_state base; 283*41137443SThomas Zimmermann }; 284*41137443SThomas Zimmermann 285*41137443SThomas Zimmermann static struct ofdrm_crtc_state *to_ofdrm_crtc_state(struct drm_crtc_state *base) 286*41137443SThomas Zimmermann { 287*41137443SThomas Zimmermann return container_of(base, struct ofdrm_crtc_state, base); 288*41137443SThomas Zimmermann } 289*41137443SThomas Zimmermann 290*41137443SThomas Zimmermann static void ofdrm_crtc_state_destroy(struct ofdrm_crtc_state *ofdrm_crtc_state) 291*41137443SThomas Zimmermann { 292*41137443SThomas Zimmermann __drm_atomic_helper_crtc_destroy_state(&ofdrm_crtc_state->base); 293*41137443SThomas Zimmermann kfree(ofdrm_crtc_state); 294*41137443SThomas Zimmermann } 295*41137443SThomas Zimmermann 296c8a17756SThomas Zimmermann /* 297c8a17756SThomas Zimmermann * Support all formats of OF display and maybe more; in order 298c8a17756SThomas Zimmermann * of preference. The display's update function will do any 299c8a17756SThomas Zimmermann * conversion necessary. 300c8a17756SThomas Zimmermann * 301c8a17756SThomas Zimmermann * TODO: Add blit helpers for remaining formats and uncomment 302c8a17756SThomas Zimmermann * constants. 303c8a17756SThomas Zimmermann */ 304c8a17756SThomas Zimmermann static const uint32_t ofdrm_primary_plane_formats[] = { 305c8a17756SThomas Zimmermann DRM_FORMAT_XRGB8888, 306c8a17756SThomas Zimmermann DRM_FORMAT_RGB565, 307c8a17756SThomas Zimmermann //DRM_FORMAT_XRGB1555, 308c8a17756SThomas Zimmermann //DRM_FORMAT_C8, 309c8a17756SThomas Zimmermann }; 310c8a17756SThomas Zimmermann 311c8a17756SThomas Zimmermann static const uint64_t ofdrm_primary_plane_format_modifiers[] = { 312c8a17756SThomas Zimmermann DRM_FORMAT_MOD_LINEAR, 313c8a17756SThomas Zimmermann DRM_FORMAT_MOD_INVALID 314c8a17756SThomas Zimmermann }; 315c8a17756SThomas Zimmermann 316c8a17756SThomas Zimmermann static int ofdrm_primary_plane_helper_atomic_check(struct drm_plane *plane, 317c8a17756SThomas Zimmermann struct drm_atomic_state *new_state) 318c8a17756SThomas Zimmermann { 319c8a17756SThomas Zimmermann struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane); 320c8a17756SThomas Zimmermann struct drm_crtc *new_crtc = new_plane_state->crtc; 321c8a17756SThomas Zimmermann struct drm_crtc_state *new_crtc_state = NULL; 322c8a17756SThomas Zimmermann 323c8a17756SThomas Zimmermann if (new_crtc) 324c8a17756SThomas Zimmermann new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc); 325c8a17756SThomas Zimmermann 326c8a17756SThomas Zimmermann return drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, 327c8a17756SThomas Zimmermann DRM_PLANE_NO_SCALING, 328c8a17756SThomas Zimmermann DRM_PLANE_NO_SCALING, 329c8a17756SThomas Zimmermann false, false); 330c8a17756SThomas Zimmermann } 331c8a17756SThomas Zimmermann 332c8a17756SThomas Zimmermann static void ofdrm_primary_plane_helper_atomic_update(struct drm_plane *plane, 333c8a17756SThomas Zimmermann struct drm_atomic_state *state) 334c8a17756SThomas Zimmermann { 335c8a17756SThomas Zimmermann struct drm_device *dev = plane->dev; 336c8a17756SThomas Zimmermann struct ofdrm_device *odev = ofdrm_device_of_dev(dev); 337c8a17756SThomas Zimmermann struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); 338c8a17756SThomas Zimmermann struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); 339c8a17756SThomas Zimmermann struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); 340c8a17756SThomas Zimmermann struct drm_framebuffer *fb = plane_state->fb; 341c8a17756SThomas Zimmermann unsigned int dst_pitch = odev->pitch; 342c8a17756SThomas Zimmermann const struct drm_format_info *dst_format = odev->format; 343c8a17756SThomas Zimmermann struct drm_atomic_helper_damage_iter iter; 344c8a17756SThomas Zimmermann struct drm_rect damage; 345c8a17756SThomas Zimmermann int ret, idx; 346c8a17756SThomas Zimmermann 347c8a17756SThomas Zimmermann ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); 348c8a17756SThomas Zimmermann if (ret) 349c8a17756SThomas Zimmermann return; 350c8a17756SThomas Zimmermann 351c8a17756SThomas Zimmermann if (!drm_dev_enter(dev, &idx)) 352c8a17756SThomas Zimmermann goto out_drm_gem_fb_end_cpu_access; 353c8a17756SThomas Zimmermann 354c8a17756SThomas Zimmermann drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); 355c8a17756SThomas Zimmermann drm_atomic_for_each_plane_damage(&iter, &damage) { 356c8a17756SThomas Zimmermann struct iosys_map dst = odev->screen_base; 357c8a17756SThomas Zimmermann struct drm_rect dst_clip = plane_state->dst; 358c8a17756SThomas Zimmermann 359c8a17756SThomas Zimmermann if (!drm_rect_intersect(&dst_clip, &damage)) 360c8a17756SThomas Zimmermann continue; 361c8a17756SThomas Zimmermann 362c8a17756SThomas Zimmermann iosys_map_incr(&dst, drm_fb_clip_offset(dst_pitch, dst_format, &dst_clip)); 363c8a17756SThomas Zimmermann drm_fb_blit(&dst, &dst_pitch, dst_format->format, shadow_plane_state->data, fb, 364c8a17756SThomas Zimmermann &damage); 365c8a17756SThomas Zimmermann } 366c8a17756SThomas Zimmermann 367c8a17756SThomas Zimmermann drm_dev_exit(idx); 368c8a17756SThomas Zimmermann out_drm_gem_fb_end_cpu_access: 369c8a17756SThomas Zimmermann drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); 370c8a17756SThomas Zimmermann } 371c8a17756SThomas Zimmermann 372c8a17756SThomas Zimmermann static void ofdrm_primary_plane_helper_atomic_disable(struct drm_plane *plane, 373c8a17756SThomas Zimmermann struct drm_atomic_state *state) 374c8a17756SThomas Zimmermann { 375c8a17756SThomas Zimmermann struct drm_device *dev = plane->dev; 376c8a17756SThomas Zimmermann struct ofdrm_device *odev = ofdrm_device_of_dev(dev); 377c8a17756SThomas Zimmermann struct iosys_map dst = odev->screen_base; 378c8a17756SThomas Zimmermann struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); 379c8a17756SThomas Zimmermann void __iomem *dst_vmap = dst.vaddr_iomem; /* TODO: Use mapping abstraction */ 380c8a17756SThomas Zimmermann unsigned int dst_pitch = odev->pitch; 381c8a17756SThomas Zimmermann const struct drm_format_info *dst_format = odev->format; 382c8a17756SThomas Zimmermann struct drm_rect dst_clip; 383c8a17756SThomas Zimmermann unsigned long lines, linepixels, i; 384c8a17756SThomas Zimmermann int idx; 385c8a17756SThomas Zimmermann 386c8a17756SThomas Zimmermann drm_rect_init(&dst_clip, 387c8a17756SThomas Zimmermann plane_state->src_x >> 16, plane_state->src_y >> 16, 388c8a17756SThomas Zimmermann plane_state->src_w >> 16, plane_state->src_h >> 16); 389c8a17756SThomas Zimmermann 390c8a17756SThomas Zimmermann lines = drm_rect_height(&dst_clip); 391c8a17756SThomas Zimmermann linepixels = drm_rect_width(&dst_clip); 392c8a17756SThomas Zimmermann 393c8a17756SThomas Zimmermann if (!drm_dev_enter(dev, &idx)) 394c8a17756SThomas Zimmermann return; 395c8a17756SThomas Zimmermann 396c8a17756SThomas Zimmermann /* Clear buffer to black if disabled */ 397c8a17756SThomas Zimmermann dst_vmap += drm_fb_clip_offset(dst_pitch, dst_format, &dst_clip); 398c8a17756SThomas Zimmermann for (i = 0; i < lines; ++i) { 399c8a17756SThomas Zimmermann memset_io(dst_vmap, 0, linepixels * dst_format->cpp[0]); 400c8a17756SThomas Zimmermann dst_vmap += dst_pitch; 401c8a17756SThomas Zimmermann } 402c8a17756SThomas Zimmermann 403c8a17756SThomas Zimmermann drm_dev_exit(idx); 404c8a17756SThomas Zimmermann } 405c8a17756SThomas Zimmermann 406c8a17756SThomas Zimmermann static const struct drm_plane_helper_funcs ofdrm_primary_plane_helper_funcs = { 407c8a17756SThomas Zimmermann DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, 408c8a17756SThomas Zimmermann .atomic_check = ofdrm_primary_plane_helper_atomic_check, 409c8a17756SThomas Zimmermann .atomic_update = ofdrm_primary_plane_helper_atomic_update, 410c8a17756SThomas Zimmermann .atomic_disable = ofdrm_primary_plane_helper_atomic_disable, 411c8a17756SThomas Zimmermann }; 412c8a17756SThomas Zimmermann 413c8a17756SThomas Zimmermann static const struct drm_plane_funcs ofdrm_primary_plane_funcs = { 414c8a17756SThomas Zimmermann .update_plane = drm_atomic_helper_update_plane, 415c8a17756SThomas Zimmermann .disable_plane = drm_atomic_helper_disable_plane, 416c8a17756SThomas Zimmermann .destroy = drm_plane_cleanup, 417c8a17756SThomas Zimmermann DRM_GEM_SHADOW_PLANE_FUNCS, 418c8a17756SThomas Zimmermann }; 419c8a17756SThomas Zimmermann 420c8a17756SThomas Zimmermann static enum drm_mode_status ofdrm_crtc_helper_mode_valid(struct drm_crtc *crtc, 421c8a17756SThomas Zimmermann const struct drm_display_mode *mode) 422c8a17756SThomas Zimmermann { 423c8a17756SThomas Zimmermann struct ofdrm_device *odev = ofdrm_device_of_dev(crtc->dev); 424c8a17756SThomas Zimmermann 425c8a17756SThomas Zimmermann return drm_crtc_helper_mode_valid_fixed(crtc, mode, &odev->mode); 426c8a17756SThomas Zimmermann } 427c8a17756SThomas Zimmermann 428c8a17756SThomas Zimmermann static int ofdrm_crtc_helper_atomic_check(struct drm_crtc *crtc, 429c8a17756SThomas Zimmermann struct drm_atomic_state *new_state) 430c8a17756SThomas Zimmermann { 431c8a17756SThomas Zimmermann struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); 432c8a17756SThomas Zimmermann 433c8a17756SThomas Zimmermann if (!new_crtc_state->enable) 434c8a17756SThomas Zimmermann return 0; 435c8a17756SThomas Zimmermann 436c8a17756SThomas Zimmermann return drm_atomic_helper_check_crtc_primary_plane(new_crtc_state); 437c8a17756SThomas Zimmermann } 438c8a17756SThomas Zimmermann 439c8a17756SThomas Zimmermann /* 440c8a17756SThomas Zimmermann * The CRTC is always enabled. Screen updates are performed by 441c8a17756SThomas Zimmermann * the primary plane's atomic_update function. Disabling clears 442c8a17756SThomas Zimmermann * the screen in the primary plane's atomic_disable function. 443c8a17756SThomas Zimmermann */ 444c8a17756SThomas Zimmermann static const struct drm_crtc_helper_funcs ofdrm_crtc_helper_funcs = { 445c8a17756SThomas Zimmermann .mode_valid = ofdrm_crtc_helper_mode_valid, 446c8a17756SThomas Zimmermann .atomic_check = ofdrm_crtc_helper_atomic_check, 447c8a17756SThomas Zimmermann }; 448c8a17756SThomas Zimmermann 449*41137443SThomas Zimmermann static void ofdrm_crtc_reset(struct drm_crtc *crtc) 450*41137443SThomas Zimmermann { 451*41137443SThomas Zimmermann struct ofdrm_crtc_state *ofdrm_crtc_state = 452*41137443SThomas Zimmermann kzalloc(sizeof(*ofdrm_crtc_state), GFP_KERNEL); 453*41137443SThomas Zimmermann 454*41137443SThomas Zimmermann if (crtc->state) 455*41137443SThomas Zimmermann ofdrm_crtc_state_destroy(to_ofdrm_crtc_state(crtc->state)); 456*41137443SThomas Zimmermann 457*41137443SThomas Zimmermann if (ofdrm_crtc_state) 458*41137443SThomas Zimmermann __drm_atomic_helper_crtc_reset(crtc, &ofdrm_crtc_state->base); 459*41137443SThomas Zimmermann else 460*41137443SThomas Zimmermann __drm_atomic_helper_crtc_reset(crtc, NULL); 461*41137443SThomas Zimmermann } 462*41137443SThomas Zimmermann 463*41137443SThomas Zimmermann static struct drm_crtc_state *ofdrm_crtc_atomic_duplicate_state(struct drm_crtc *crtc) 464*41137443SThomas Zimmermann { 465*41137443SThomas Zimmermann struct drm_device *dev = crtc->dev; 466*41137443SThomas Zimmermann struct drm_crtc_state *crtc_state = crtc->state; 467*41137443SThomas Zimmermann struct ofdrm_crtc_state *new_ofdrm_crtc_state; 468*41137443SThomas Zimmermann 469*41137443SThomas Zimmermann if (drm_WARN_ON(dev, !crtc_state)) 470*41137443SThomas Zimmermann return NULL; 471*41137443SThomas Zimmermann 472*41137443SThomas Zimmermann new_ofdrm_crtc_state = kzalloc(sizeof(*new_ofdrm_crtc_state), GFP_KERNEL); 473*41137443SThomas Zimmermann if (!new_ofdrm_crtc_state) 474*41137443SThomas Zimmermann return NULL; 475*41137443SThomas Zimmermann 476*41137443SThomas Zimmermann __drm_atomic_helper_crtc_duplicate_state(crtc, &new_ofdrm_crtc_state->base); 477*41137443SThomas Zimmermann 478*41137443SThomas Zimmermann return &new_ofdrm_crtc_state->base; 479*41137443SThomas Zimmermann } 480*41137443SThomas Zimmermann 481*41137443SThomas Zimmermann static void ofdrm_crtc_atomic_destroy_state(struct drm_crtc *crtc, 482*41137443SThomas Zimmermann struct drm_crtc_state *crtc_state) 483*41137443SThomas Zimmermann { 484*41137443SThomas Zimmermann ofdrm_crtc_state_destroy(to_ofdrm_crtc_state(crtc_state)); 485*41137443SThomas Zimmermann } 486*41137443SThomas Zimmermann 487c8a17756SThomas Zimmermann static const struct drm_crtc_funcs ofdrm_crtc_funcs = { 488*41137443SThomas Zimmermann .reset = ofdrm_crtc_reset, 489c8a17756SThomas Zimmermann .destroy = drm_crtc_cleanup, 490c8a17756SThomas Zimmermann .set_config = drm_atomic_helper_set_config, 491c8a17756SThomas Zimmermann .page_flip = drm_atomic_helper_page_flip, 492*41137443SThomas Zimmermann .atomic_duplicate_state = ofdrm_crtc_atomic_duplicate_state, 493*41137443SThomas Zimmermann .atomic_destroy_state = ofdrm_crtc_atomic_destroy_state, 494c8a17756SThomas Zimmermann }; 495c8a17756SThomas Zimmermann 496c8a17756SThomas Zimmermann static int ofdrm_connector_helper_get_modes(struct drm_connector *connector) 497c8a17756SThomas Zimmermann { 498c8a17756SThomas Zimmermann struct ofdrm_device *odev = ofdrm_device_of_dev(connector->dev); 499c8a17756SThomas Zimmermann 500c8a17756SThomas Zimmermann return drm_connector_helper_get_modes_fixed(connector, &odev->mode); 501c8a17756SThomas Zimmermann } 502c8a17756SThomas Zimmermann 503c8a17756SThomas Zimmermann static const struct drm_connector_helper_funcs ofdrm_connector_helper_funcs = { 504c8a17756SThomas Zimmermann .get_modes = ofdrm_connector_helper_get_modes, 505c8a17756SThomas Zimmermann }; 506c8a17756SThomas Zimmermann 507c8a17756SThomas Zimmermann static const struct drm_connector_funcs ofdrm_connector_funcs = { 508c8a17756SThomas Zimmermann .reset = drm_atomic_helper_connector_reset, 509c8a17756SThomas Zimmermann .fill_modes = drm_helper_probe_single_connector_modes, 510c8a17756SThomas Zimmermann .destroy = drm_connector_cleanup, 511c8a17756SThomas Zimmermann .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 512c8a17756SThomas Zimmermann .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 513c8a17756SThomas Zimmermann }; 514c8a17756SThomas Zimmermann 515c8a17756SThomas Zimmermann static const struct drm_mode_config_funcs ofdrm_mode_config_funcs = { 516c8a17756SThomas Zimmermann .fb_create = drm_gem_fb_create_with_dirty, 517c8a17756SThomas Zimmermann .atomic_check = drm_atomic_helper_check, 518c8a17756SThomas Zimmermann .atomic_commit = drm_atomic_helper_commit, 519c8a17756SThomas Zimmermann }; 520c8a17756SThomas Zimmermann 521c8a17756SThomas Zimmermann /* 522c8a17756SThomas Zimmermann * Init / Cleanup 523c8a17756SThomas Zimmermann */ 524c8a17756SThomas Zimmermann 525c8a17756SThomas Zimmermann static struct drm_display_mode ofdrm_mode(unsigned int width, unsigned int height) 526c8a17756SThomas Zimmermann { 527c8a17756SThomas Zimmermann /* 528c8a17756SThomas Zimmermann * Assume a monitor resolution of 96 dpi to 529c8a17756SThomas Zimmermann * get a somewhat reasonable screen size. 530c8a17756SThomas Zimmermann */ 531c8a17756SThomas Zimmermann const struct drm_display_mode mode = { 532c8a17756SThomas Zimmermann DRM_MODE_INIT(60, width, height, 533c8a17756SThomas Zimmermann DRM_MODE_RES_MM(width, 96ul), 534c8a17756SThomas Zimmermann DRM_MODE_RES_MM(height, 96ul)) 535c8a17756SThomas Zimmermann }; 536c8a17756SThomas Zimmermann 537c8a17756SThomas Zimmermann return mode; 538c8a17756SThomas Zimmermann } 539c8a17756SThomas Zimmermann 540c8a17756SThomas Zimmermann static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv, 541c8a17756SThomas Zimmermann struct platform_device *pdev) 542c8a17756SThomas Zimmermann { 543c8a17756SThomas Zimmermann struct device_node *of_node = pdev->dev.of_node; 544c8a17756SThomas Zimmermann struct ofdrm_device *odev; 545c8a17756SThomas Zimmermann struct drm_device *dev; 546c8a17756SThomas Zimmermann int width, height, depth, linebytes; 547c8a17756SThomas Zimmermann const struct drm_format_info *format; 548c8a17756SThomas Zimmermann u64 address; 549c8a17756SThomas Zimmermann resource_size_t fb_size, fb_base, fb_pgbase, fb_pgsize; 550c8a17756SThomas Zimmermann struct resource *res, *mem; 551c8a17756SThomas Zimmermann void __iomem *screen_base; 552c8a17756SThomas Zimmermann struct drm_plane *primary_plane; 553c8a17756SThomas Zimmermann struct drm_crtc *crtc; 554c8a17756SThomas Zimmermann struct drm_encoder *encoder; 555c8a17756SThomas Zimmermann struct drm_connector *connector; 556c8a17756SThomas Zimmermann unsigned long max_width, max_height; 557c8a17756SThomas Zimmermann size_t nformats; 558c8a17756SThomas Zimmermann int ret; 559c8a17756SThomas Zimmermann 560c8a17756SThomas Zimmermann odev = devm_drm_dev_alloc(&pdev->dev, drv, struct ofdrm_device, dev); 561c8a17756SThomas Zimmermann if (IS_ERR(odev)) 562c8a17756SThomas Zimmermann return ERR_CAST(odev); 563c8a17756SThomas Zimmermann dev = &odev->dev; 564c8a17756SThomas Zimmermann platform_set_drvdata(pdev, dev); 565c8a17756SThomas Zimmermann 566c8a17756SThomas Zimmermann ret = ofdrm_device_init_pci(odev); 567c8a17756SThomas Zimmermann if (ret) 568c8a17756SThomas Zimmermann return ERR_PTR(ret); 569c8a17756SThomas Zimmermann 570c8a17756SThomas Zimmermann /* 571c8a17756SThomas Zimmermann * OF display-node settings 572c8a17756SThomas Zimmermann */ 573c8a17756SThomas Zimmermann 574c8a17756SThomas Zimmermann width = display_get_width_of(dev, of_node); 575c8a17756SThomas Zimmermann if (width < 0) 576c8a17756SThomas Zimmermann return ERR_PTR(width); 577c8a17756SThomas Zimmermann height = display_get_height_of(dev, of_node); 578c8a17756SThomas Zimmermann if (height < 0) 579c8a17756SThomas Zimmermann return ERR_PTR(height); 580c8a17756SThomas Zimmermann depth = display_get_depth_of(dev, of_node); 581c8a17756SThomas Zimmermann if (depth < 0) 582c8a17756SThomas Zimmermann return ERR_PTR(depth); 583c8a17756SThomas Zimmermann linebytes = display_get_linebytes_of(dev, of_node); 584c8a17756SThomas Zimmermann if (linebytes < 0) 585c8a17756SThomas Zimmermann return ERR_PTR(linebytes); 586c8a17756SThomas Zimmermann 587c8a17756SThomas Zimmermann format = display_get_validated_format(dev, depth); 588c8a17756SThomas Zimmermann if (IS_ERR(format)) 589c8a17756SThomas Zimmermann return ERR_CAST(format); 590c8a17756SThomas Zimmermann if (!linebytes) { 591c8a17756SThomas Zimmermann linebytes = drm_format_info_min_pitch(format, 0, width); 592c8a17756SThomas Zimmermann if (drm_WARN_ON(dev, !linebytes)) 593c8a17756SThomas Zimmermann return ERR_PTR(-EINVAL); 594c8a17756SThomas Zimmermann } 595c8a17756SThomas Zimmermann 596c8a17756SThomas Zimmermann fb_size = linebytes * height; 597c8a17756SThomas Zimmermann 598c8a17756SThomas Zimmermann /* 599c8a17756SThomas Zimmermann * Try to figure out the address of the framebuffer. Unfortunately, Open 600c8a17756SThomas Zimmermann * Firmware doesn't provide a standard way to do so. All we can do is a 601c8a17756SThomas Zimmermann * dodgy heuristic that happens to work in practice. 602c8a17756SThomas Zimmermann * 603c8a17756SThomas Zimmermann * On most machines, the "address" property contains what we need, though 604c8a17756SThomas Zimmermann * not on Matrox cards found in IBM machines. What appears to give good 605c8a17756SThomas Zimmermann * results is to go through the PCI ranges and pick one that encloses the 606c8a17756SThomas Zimmermann * "address" property. If none match, we pick the largest. 607c8a17756SThomas Zimmermann */ 608c8a17756SThomas Zimmermann address = display_get_address_of(dev, of_node); 609c8a17756SThomas Zimmermann if (address != OF_BAD_ADDR) { 610c8a17756SThomas Zimmermann struct resource fb_res = DEFINE_RES_MEM(address, fb_size); 611c8a17756SThomas Zimmermann 612c8a17756SThomas Zimmermann res = ofdrm_find_fb_resource(odev, &fb_res); 613c8a17756SThomas Zimmermann if (!res) 614c8a17756SThomas Zimmermann return ERR_PTR(-EINVAL); 615c8a17756SThomas Zimmermann if (resource_contains(res, &fb_res)) 616c8a17756SThomas Zimmermann fb_base = address; 617c8a17756SThomas Zimmermann else 618c8a17756SThomas Zimmermann fb_base = res->start; 619c8a17756SThomas Zimmermann } else { 620c8a17756SThomas Zimmermann struct resource fb_res = DEFINE_RES_MEM(0u, fb_size); 621c8a17756SThomas Zimmermann 622c8a17756SThomas Zimmermann res = ofdrm_find_fb_resource(odev, &fb_res); 623c8a17756SThomas Zimmermann if (!res) 624c8a17756SThomas Zimmermann return ERR_PTR(-EINVAL); 625c8a17756SThomas Zimmermann fb_base = res->start; 626c8a17756SThomas Zimmermann } 627c8a17756SThomas Zimmermann 628c8a17756SThomas Zimmermann /* 629c8a17756SThomas Zimmermann * I/O resources 630c8a17756SThomas Zimmermann */ 631c8a17756SThomas Zimmermann 632c8a17756SThomas Zimmermann fb_pgbase = round_down(fb_base, PAGE_SIZE); 633c8a17756SThomas Zimmermann fb_pgsize = fb_base - fb_pgbase + round_up(fb_size, PAGE_SIZE); 634c8a17756SThomas Zimmermann 635c8a17756SThomas Zimmermann ret = devm_aperture_acquire_from_firmware(dev, fb_pgbase, fb_pgsize); 636c8a17756SThomas Zimmermann if (ret) { 637c8a17756SThomas Zimmermann drm_err(dev, "could not acquire memory range %pr: error %d\n", &res, ret); 638c8a17756SThomas Zimmermann return ERR_PTR(ret); 639c8a17756SThomas Zimmermann } 640c8a17756SThomas Zimmermann 641c8a17756SThomas Zimmermann mem = devm_request_mem_region(&pdev->dev, fb_pgbase, fb_pgsize, drv->name); 642c8a17756SThomas Zimmermann if (!mem) { 643c8a17756SThomas Zimmermann drm_warn(dev, "could not acquire memory region %pr\n", &res); 644c8a17756SThomas Zimmermann return ERR_PTR(-ENOMEM); 645c8a17756SThomas Zimmermann } 646c8a17756SThomas Zimmermann 647c8a17756SThomas Zimmermann screen_base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); 648c8a17756SThomas Zimmermann if (!screen_base) 649c8a17756SThomas Zimmermann return ERR_PTR(-ENOMEM); 650c8a17756SThomas Zimmermann 651c8a17756SThomas Zimmermann /* 652c8a17756SThomas Zimmermann * Firmware framebuffer 653c8a17756SThomas Zimmermann */ 654c8a17756SThomas Zimmermann 655c8a17756SThomas Zimmermann iosys_map_set_vaddr_iomem(&odev->screen_base, screen_base); 656c8a17756SThomas Zimmermann odev->mode = ofdrm_mode(width, height); 657c8a17756SThomas Zimmermann odev->format = format; 658c8a17756SThomas Zimmermann odev->pitch = linebytes; 659c8a17756SThomas Zimmermann 660c8a17756SThomas Zimmermann drm_dbg(dev, "display mode={" DRM_MODE_FMT "}\n", DRM_MODE_ARG(&odev->mode)); 661c8a17756SThomas Zimmermann drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, linebytes=%d byte\n", 662c8a17756SThomas Zimmermann &format->format, width, height, linebytes); 663c8a17756SThomas Zimmermann 664c8a17756SThomas Zimmermann /* 665c8a17756SThomas Zimmermann * Mode-setting pipeline 666c8a17756SThomas Zimmermann */ 667c8a17756SThomas Zimmermann 668c8a17756SThomas Zimmermann ret = drmm_mode_config_init(dev); 669c8a17756SThomas Zimmermann if (ret) 670c8a17756SThomas Zimmermann return ERR_PTR(ret); 671c8a17756SThomas Zimmermann 672c8a17756SThomas Zimmermann max_width = max_t(unsigned long, width, DRM_SHADOW_PLANE_MAX_WIDTH); 673c8a17756SThomas Zimmermann max_height = max_t(unsigned long, height, DRM_SHADOW_PLANE_MAX_HEIGHT); 674c8a17756SThomas Zimmermann 675c8a17756SThomas Zimmermann dev->mode_config.min_width = width; 676c8a17756SThomas Zimmermann dev->mode_config.max_width = max_width; 677c8a17756SThomas Zimmermann dev->mode_config.min_height = height; 678c8a17756SThomas Zimmermann dev->mode_config.max_height = max_height; 679c8a17756SThomas Zimmermann dev->mode_config.funcs = &ofdrm_mode_config_funcs; 680c8a17756SThomas Zimmermann switch (depth) { 681c8a17756SThomas Zimmermann case 32: 682c8a17756SThomas Zimmermann dev->mode_config.preferred_depth = 24; 683c8a17756SThomas Zimmermann break; 684c8a17756SThomas Zimmermann default: 685c8a17756SThomas Zimmermann dev->mode_config.preferred_depth = depth; 686c8a17756SThomas Zimmermann break; 687c8a17756SThomas Zimmermann } 688c8a17756SThomas Zimmermann 689c8a17756SThomas Zimmermann /* Primary plane */ 690c8a17756SThomas Zimmermann 691c8a17756SThomas Zimmermann nformats = drm_fb_build_fourcc_list(dev, &format->format, 1, 692c8a17756SThomas Zimmermann ofdrm_primary_plane_formats, 693c8a17756SThomas Zimmermann ARRAY_SIZE(ofdrm_primary_plane_formats), 694c8a17756SThomas Zimmermann odev->formats, ARRAY_SIZE(odev->formats)); 695c8a17756SThomas Zimmermann 696c8a17756SThomas Zimmermann primary_plane = &odev->primary_plane; 697c8a17756SThomas Zimmermann ret = drm_universal_plane_init(dev, primary_plane, 0, &ofdrm_primary_plane_funcs, 698c8a17756SThomas Zimmermann odev->formats, nformats, 699c8a17756SThomas Zimmermann ofdrm_primary_plane_format_modifiers, 700c8a17756SThomas Zimmermann DRM_PLANE_TYPE_PRIMARY, NULL); 701c8a17756SThomas Zimmermann if (ret) 702c8a17756SThomas Zimmermann return ERR_PTR(ret); 703c8a17756SThomas Zimmermann drm_plane_helper_add(primary_plane, &ofdrm_primary_plane_helper_funcs); 704c8a17756SThomas Zimmermann drm_plane_enable_fb_damage_clips(primary_plane); 705c8a17756SThomas Zimmermann 706c8a17756SThomas Zimmermann /* CRTC */ 707c8a17756SThomas Zimmermann 708c8a17756SThomas Zimmermann crtc = &odev->crtc; 709c8a17756SThomas Zimmermann ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, 710c8a17756SThomas Zimmermann &ofdrm_crtc_funcs, NULL); 711c8a17756SThomas Zimmermann if (ret) 712c8a17756SThomas Zimmermann return ERR_PTR(ret); 713c8a17756SThomas Zimmermann drm_crtc_helper_add(crtc, &ofdrm_crtc_helper_funcs); 714c8a17756SThomas Zimmermann 715c8a17756SThomas Zimmermann /* Encoder */ 716c8a17756SThomas Zimmermann 717c8a17756SThomas Zimmermann encoder = &odev->encoder; 718c8a17756SThomas Zimmermann ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_NONE); 719c8a17756SThomas Zimmermann if (ret) 720c8a17756SThomas Zimmermann return ERR_PTR(ret); 721c8a17756SThomas Zimmermann encoder->possible_crtcs = drm_crtc_mask(crtc); 722c8a17756SThomas Zimmermann 723c8a17756SThomas Zimmermann /* Connector */ 724c8a17756SThomas Zimmermann 725c8a17756SThomas Zimmermann connector = &odev->connector; 726c8a17756SThomas Zimmermann ret = drm_connector_init(dev, connector, &ofdrm_connector_funcs, 727c8a17756SThomas Zimmermann DRM_MODE_CONNECTOR_Unknown); 728c8a17756SThomas Zimmermann if (ret) 729c8a17756SThomas Zimmermann return ERR_PTR(ret); 730c8a17756SThomas Zimmermann drm_connector_helper_add(connector, &ofdrm_connector_helper_funcs); 731c8a17756SThomas Zimmermann drm_connector_set_panel_orientation_with_quirk(connector, 732c8a17756SThomas Zimmermann DRM_MODE_PANEL_ORIENTATION_UNKNOWN, 733c8a17756SThomas Zimmermann width, height); 734c8a17756SThomas Zimmermann 735c8a17756SThomas Zimmermann ret = drm_connector_attach_encoder(connector, encoder); 736c8a17756SThomas Zimmermann if (ret) 737c8a17756SThomas Zimmermann return ERR_PTR(ret); 738c8a17756SThomas Zimmermann 739c8a17756SThomas Zimmermann drm_mode_config_reset(dev); 740c8a17756SThomas Zimmermann 741c8a17756SThomas Zimmermann return odev; 742c8a17756SThomas Zimmermann } 743c8a17756SThomas Zimmermann 744c8a17756SThomas Zimmermann /* 745c8a17756SThomas Zimmermann * DRM driver 746c8a17756SThomas Zimmermann */ 747c8a17756SThomas Zimmermann 748c8a17756SThomas Zimmermann DEFINE_DRM_GEM_FOPS(ofdrm_fops); 749c8a17756SThomas Zimmermann 750c8a17756SThomas Zimmermann static struct drm_driver ofdrm_driver = { 751c8a17756SThomas Zimmermann DRM_GEM_SHMEM_DRIVER_OPS, 752c8a17756SThomas Zimmermann .name = DRIVER_NAME, 753c8a17756SThomas Zimmermann .desc = DRIVER_DESC, 754c8a17756SThomas Zimmermann .date = DRIVER_DATE, 755c8a17756SThomas Zimmermann .major = DRIVER_MAJOR, 756c8a17756SThomas Zimmermann .minor = DRIVER_MINOR, 757c8a17756SThomas Zimmermann .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET, 758c8a17756SThomas Zimmermann .fops = &ofdrm_fops, 759c8a17756SThomas Zimmermann }; 760c8a17756SThomas Zimmermann 761c8a17756SThomas Zimmermann /* 762c8a17756SThomas Zimmermann * Platform driver 763c8a17756SThomas Zimmermann */ 764c8a17756SThomas Zimmermann 765c8a17756SThomas Zimmermann static int ofdrm_probe(struct platform_device *pdev) 766c8a17756SThomas Zimmermann { 767c8a17756SThomas Zimmermann struct ofdrm_device *odev; 768c8a17756SThomas Zimmermann struct drm_device *dev; 769c8a17756SThomas Zimmermann int ret; 770c8a17756SThomas Zimmermann 771c8a17756SThomas Zimmermann odev = ofdrm_device_create(&ofdrm_driver, pdev); 772c8a17756SThomas Zimmermann if (IS_ERR(odev)) 773c8a17756SThomas Zimmermann return PTR_ERR(odev); 774c8a17756SThomas Zimmermann dev = &odev->dev; 775c8a17756SThomas Zimmermann 776c8a17756SThomas Zimmermann ret = drm_dev_register(dev, 0); 777c8a17756SThomas Zimmermann if (ret) 778c8a17756SThomas Zimmermann return ret; 779c8a17756SThomas Zimmermann 780c8a17756SThomas Zimmermann /* 781c8a17756SThomas Zimmermann * FIXME: 24-bit color depth does not work reliably with a 32-bpp 782c8a17756SThomas Zimmermann * value. Force the bpp value of the scanout buffer's format. 783c8a17756SThomas Zimmermann */ 784c8a17756SThomas Zimmermann drm_fbdev_generic_setup(dev, drm_format_info_bpp(odev->format, 0)); 785c8a17756SThomas Zimmermann 786c8a17756SThomas Zimmermann return 0; 787c8a17756SThomas Zimmermann } 788c8a17756SThomas Zimmermann 789c8a17756SThomas Zimmermann static int ofdrm_remove(struct platform_device *pdev) 790c8a17756SThomas Zimmermann { 791c8a17756SThomas Zimmermann struct drm_device *dev = platform_get_drvdata(pdev); 792c8a17756SThomas Zimmermann 793c8a17756SThomas Zimmermann drm_dev_unplug(dev); 794c8a17756SThomas Zimmermann 795c8a17756SThomas Zimmermann return 0; 796c8a17756SThomas Zimmermann } 797c8a17756SThomas Zimmermann 798c8a17756SThomas Zimmermann static const struct of_device_id ofdrm_of_match_display[] = { 799c8a17756SThomas Zimmermann { .compatible = "display", }, 800c8a17756SThomas Zimmermann { }, 801c8a17756SThomas Zimmermann }; 802c8a17756SThomas Zimmermann MODULE_DEVICE_TABLE(of, ofdrm_of_match_display); 803c8a17756SThomas Zimmermann 804c8a17756SThomas Zimmermann static struct platform_driver ofdrm_platform_driver = { 805c8a17756SThomas Zimmermann .driver = { 806c8a17756SThomas Zimmermann .name = "of-display", 807c8a17756SThomas Zimmermann .of_match_table = ofdrm_of_match_display, 808c8a17756SThomas Zimmermann }, 809c8a17756SThomas Zimmermann .probe = ofdrm_probe, 810c8a17756SThomas Zimmermann .remove = ofdrm_remove, 811c8a17756SThomas Zimmermann }; 812c8a17756SThomas Zimmermann 813c8a17756SThomas Zimmermann module_platform_driver(ofdrm_platform_driver); 814c8a17756SThomas Zimmermann 815c8a17756SThomas Zimmermann MODULE_DESCRIPTION(DRIVER_DESC); 816c8a17756SThomas Zimmermann MODULE_LICENSE("GPL"); 817