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