| 1 | |
| 2 |
|
| 3 | #include <linux/aperture.h>
|
| 4 | #include <linux/of_address.h>
|
| 5 | #include <linux/overflow.h>
|
| 6 | #include <linux/pci.h>
|
| 7 | #include <linux/platform_device.h>
|
| 8 | #include <linux/pm.h>
|
| 9 |
|
| 10 | #include <drm/clients/drm_client_setup.h>
|
| 11 | #include <drm/drm_atomic.h>
|
| 12 | #include <drm/drm_atomic_state_helper.h>
|
| 13 | #include <drm/drm_color_mgmt.h>
|
| 14 | #include <drm/drm_connector.h>
|
| 15 | #include <drm/drm_damage_helper.h>
|
| 16 | #include <drm/drm_device.h>
|
| 17 | #include <drm/drm_drv.h>
|
| 18 | #include <drm/drm_edid.h>
|
| 19 | #include <drm/drm_fbdev_shmem.h>
|
| 20 | #include <drm/drm_framebuffer.h>
|
| 21 | #include <drm/drm_gem_atomic_helper.h>
|
| 22 | #include <drm/drm_gem_framebuffer_helper.h>
|
| 23 | #include <drm/drm_gem_shmem_helper.h>
|
| 24 | #include <drm/drm_managed.h>
|
| 25 | #include <drm/drm_modeset_helper.h>
|
| 26 | #include <drm/drm_modeset_helper_vtables.h>
|
| 27 | #include <drm/drm_print.h>
|
| 28 | #include <drm/drm_probe_helper.h>
|
| 29 |
|
| 30 | #include "drm_sysfb_helper.h"
|
| 31 |
|
| 32 | #define DRIVER_NAME "ofdrm"
|
| 33 | #define DRIVER_DESC "DRM driver for OF platform devices"
|
| 34 | #define DRIVER_MAJOR 1
|
| 35 | #define DRIVER_MINOR 0
|
| 36 |
|
| 37 | #define PCI_VENDOR_ID_ATI_R520 0x7100
|
| 38 | #define PCI_VENDOR_ID_ATI_R600 0x9400
|
| 39 |
|
| 40 | #define OFDRM_GAMMA_LUT_SIZE 256
|
| 41 |
|
| 42 |
|
| 43 | #define AVIVO_DC_LUT_RW_SELECT 0x6480
|
| 44 | #define AVIVO_DC_LUT_RW_MODE 0x6484
|
| 45 | #define AVIVO_DC_LUT_RW_INDEX 0x6488
|
| 46 | #define AVIVO_DC_LUT_SEQ_COLOR 0x648c
|
| 47 | #define AVIVO_DC_LUT_PWL_DATA 0x6490
|
| 48 | #define AVIVO_DC_LUT_30_COLOR 0x6494
|
| 49 | #define AVIVO_DC_LUT_READ_PIPE_SELECT 0x6498
|
| 50 | #define AVIVO_DC_LUT_WRITE_EN_MASK 0x649c
|
| 51 | #define AVIVO_DC_LUT_AUTOFILL 0x64a0
|
| 52 | #define AVIVO_DC_LUTA_CONTROL 0x64c0
|
| 53 | #define AVIVO_DC_LUTA_BLACK_OFFSET_BLUE 0x64c4
|
| 54 | #define AVIVO_DC_LUTA_BLACK_OFFSET_GREEN 0x64c8
|
| 55 | #define AVIVO_DC_LUTA_BLACK_OFFSET_RED 0x64cc
|
| 56 | #define AVIVO_DC_LUTA_WHITE_OFFSET_BLUE 0x64d0
|
| 57 | #define AVIVO_DC_LUTA_WHITE_OFFSET_GREEN 0x64d4
|
| 58 | #define AVIVO_DC_LUTA_WHITE_OFFSET_RED 0x64d8
|
| 59 | #define AVIVO_DC_LUTB_CONTROL 0x6cc0
|
| 60 | #define AVIVO_DC_LUTB_BLACK_OFFSET_BLUE 0x6cc4
|
| 61 | #define AVIVO_DC_LUTB_BLACK_OFFSET_GREEN 0x6cc8
|
| 62 | #define AVIVO_DC_LUTB_BLACK_OFFSET_RED 0x6ccc
|
| 63 | #define AVIVO_DC_LUTB_WHITE_OFFSET_BLUE 0x6cd0
|
| 64 | #define AVIVO_DC_LUTB_WHITE_OFFSET_GREEN 0x6cd4
|
| 65 | #define AVIVO_DC_LUTB_WHITE_OFFSET_RED 0x6cd8
|
| 66 |
|
| 67 | enum ofdrm_model {
|
| 68 | OFDRM_MODEL_UNKNOWN,
|
| 69 | OFDRM_MODEL_MACH64,
|
| 70 | OFDRM_MODEL_RAGE128,
|
| 71 | OFDRM_MODEL_RAGE_M3A,
|
| 72 | OFDRM_MODEL_RAGE_M3B,
|
| 73 | OFDRM_MODEL_RADEON,
|
| 74 | OFDRM_MODEL_GXT2000,
|
| 75 | OFDRM_MODEL_AVIVO,
|
| 76 | OFDRM_MODEL_QEMU,
|
| 77 | };
|
| 78 |
|
| 79 | |
| 80 | * Helpers for display nodes
|
| 81 |
|
| 82 |
|
| 83 | static int display_get_validated_int(struct drm_device *dev, const char *name, uint32_t value)
|
| 84 | {
|
| 85 | return drm_sysfb_get_validated_int(dev, name, value, INT_MAX);
|
| 86 | }
|
| 87 |
|
| 88 | static int display_get_validated_int0(struct drm_device *dev, const char *name, uint32_t value)
|
| 89 | {
|
| 90 | return drm_sysfb_get_validated_int0(dev, name, value, INT_MAX);
|
| 91 | }
|
| 92 |
|
| 93 | static const struct drm_format_info *display_get_validated_format(struct drm_device *dev,
|
| 94 | u32 depth, bool big_endian)
|
| 95 | {
|
| 96 | const struct drm_format_info *info;
|
| 97 | u32 format;
|
| 98 |
|
| 99 | switch (depth) {
|
| 100 | case 8:
|
| 101 | format = drm_mode_legacy_fb_format(8, 8);
|
| 102 | break;
|
| 103 | case 15:
|
| 104 | case 16:
|
| 105 | format = drm_mode_legacy_fb_format(16, depth);
|
| 106 | break;
|
| 107 | case 32:
|
| 108 | format = drm_mode_legacy_fb_format(32, 24);
|
| 109 | break;
|
| 110 | default:
|
| 111 | drm_err(dev, "unsupported framebuffer depth %u\n", depth);
|
| 112 | return ERR_PTR(-EINVAL);
|
| 113 | }
|
| 114 |
|
| 115 | |
| 116 | * DRM formats assume little-endian byte order. Update the format
|
| 117 | * if the scanout buffer uses big-endian ordering.
|
| 118 |
|
| 119 | if (big_endian) {
|
| 120 | switch (format) {
|
| 121 | case DRM_FORMAT_XRGB8888:
|
| 122 | format = DRM_FORMAT_BGRX8888;
|
| 123 | break;
|
| 124 | case DRM_FORMAT_ARGB8888:
|
| 125 | format = DRM_FORMAT_BGRA8888;
|
| 126 | break;
|
| 127 | case DRM_FORMAT_RGB565:
|
| 128 | format = DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN;
|
| 129 | break;
|
| 130 | case DRM_FORMAT_XRGB1555:
|
| 131 | format = DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN;
|
| 132 | break;
|
| 133 | default:
|
| 134 | break;
|
| 135 | }
|
| 136 | }
|
| 137 |
|
| 138 | info = drm_format_info(format);
|
| 139 | if (!info) {
|
| 140 | drm_err(dev, "cannot find framebuffer format for depth %u\n", depth);
|
| 141 | return ERR_PTR(-EINVAL);
|
| 142 | }
|
| 143 |
|
| 144 | return info;
|
| 145 | }
|
| 146 |
|
| 147 | static int display_read_u32_of(struct drm_device *dev, struct device_node *of_node,
|
| 148 | const char *name, u32 *value)
|
| 149 | {
|
| 150 | int ret = of_property_read_u32(of_node, name, value);
|
| 151 |
|
| 152 | if (ret)
|
| 153 | drm_err(dev, "cannot parse framebuffer %s: error %d\n", name, ret);
|
| 154 | return ret;
|
| 155 | }
|
| 156 |
|
| 157 | static bool display_get_big_endian_of(struct drm_device *dev, struct device_node *of_node)
|
| 158 | {
|
| 159 | bool big_endian;
|
| 160 |
|
| 161 | #ifdef __BIG_ENDIAN
|
| 162 | big_endian = !of_property_read_bool(of_node, "little-endian");
|
| 163 | #else
|
| 164 | big_endian = of_property_read_bool(of_node, "big-endian");
|
| 165 | #endif
|
| 166 |
|
| 167 | return big_endian;
|
| 168 | }
|
| 169 |
|
| 170 | static int display_get_width_of(struct drm_device *dev, struct device_node *of_node)
|
| 171 | {
|
| 172 | u32 width;
|
| 173 | int ret = display_read_u32_of(dev, of_node, "width", &width);
|
| 174 |
|
| 175 | if (ret)
|
| 176 | return ret;
|
| 177 | return display_get_validated_int0(dev, "width", width);
|
| 178 | }
|
| 179 |
|
| 180 | static int display_get_height_of(struct drm_device *dev, struct device_node *of_node)
|
| 181 | {
|
| 182 | u32 height;
|
| 183 | int ret = display_read_u32_of(dev, of_node, "height", &height);
|
| 184 |
|
| 185 | if (ret)
|
| 186 | return ret;
|
| 187 | return display_get_validated_int0(dev, "height", height);
|
| 188 | }
|
| 189 |
|
| 190 | static int display_get_depth_of(struct drm_device *dev, struct device_node *of_node)
|
| 191 | {
|
| 192 | u32 depth;
|
| 193 | int ret = display_read_u32_of(dev, of_node, "depth", &depth);
|
| 194 |
|
| 195 | if (ret)
|
| 196 | return ret;
|
| 197 | return display_get_validated_int0(dev, "depth", depth);
|
| 198 | }
|
| 199 |
|
| 200 | static int display_get_linebytes_of(struct drm_device *dev, struct device_node *of_node)
|
| 201 | {
|
| 202 | u32 linebytes;
|
| 203 | int ret = display_read_u32_of(dev, of_node, "linebytes", &linebytes);
|
| 204 |
|
| 205 | if (ret)
|
| 206 | return ret;
|
| 207 | return display_get_validated_int(dev, "linebytes", linebytes);
|
| 208 | }
|
| 209 |
|
| 210 | static u64 display_get_address_of(struct drm_device *dev, struct device_node *of_node)
|
| 211 | {
|
| 212 | u32 address;
|
| 213 | int ret;
|
| 214 |
|
| 215 | |
| 216 | * Not all devices provide an address property, it's not
|
| 217 | * a bug if this fails. The driver will try to find the
|
| 218 | * framebuffer base address from the device's memory regions.
|
| 219 |
|
| 220 | ret = of_property_read_u32(of_node, "address", &address);
|
| 221 | if (ret)
|
| 222 | return OF_BAD_ADDR;
|
| 223 |
|
| 224 | return address;
|
| 225 | }
|
| 226 |
|
| 227 | static const u8 *display_get_edid_of(struct drm_device *dev, struct device_node *of_node,
|
| 228 | u8 buf[EDID_LENGTH])
|
| 229 | {
|
| 230 | int ret = of_property_read_u8_array(of_node, "EDID", buf, EDID_LENGTH);
|
| 231 |
|
| 232 | if (ret)
|
| 233 | return NULL;
|
| 234 | return buf;
|
| 235 | }
|
| 236 |
|
| 237 | static bool is_avivo(u32 vendor, u32 device)
|
| 238 | {
|
| 239 |
|
| 240 | return (vendor == PCI_VENDOR_ID_ATI) &&
|
| 241 | ((device >= PCI_VENDOR_ID_ATI_R520 && device < 0x7800) ||
|
| 242 | (device >= PCI_VENDOR_ID_ATI_R600));
|
| 243 | }
|
| 244 |
|
| 245 | static enum ofdrm_model display_get_model_of(struct drm_device *dev, struct device_node *of_node)
|
| 246 | {
|
| 247 | enum ofdrm_model model = OFDRM_MODEL_UNKNOWN;
|
| 248 |
|
| 249 | if (of_node_name_prefix(of_node, "ATY,Rage128")) {
|
| 250 | model = OFDRM_MODEL_RAGE128;
|
| 251 | } else if (of_node_name_prefix(of_node, "ATY,RageM3pA") ||
|
| 252 | of_node_name_prefix(of_node, "ATY,RageM3p12A")) {
|
| 253 | model = OFDRM_MODEL_RAGE_M3A;
|
| 254 | } else if (of_node_name_prefix(of_node, "ATY,RageM3pB")) {
|
| 255 | model = OFDRM_MODEL_RAGE_M3B;
|
| 256 | } else if (of_node_name_prefix(of_node, "ATY,Rage6")) {
|
| 257 | model = OFDRM_MODEL_RADEON;
|
| 258 | } else if (of_node_name_prefix(of_node, "ATY,")) {
|
| 259 | return OFDRM_MODEL_MACH64;
|
| 260 | } else if (of_device_is_compatible(of_node, "pci1014,b7") ||
|
| 261 | of_device_is_compatible(of_node, "pci1014,21c")) {
|
| 262 | model = OFDRM_MODEL_GXT2000;
|
| 263 | } else if (of_node_name_prefix(of_node, "vga,Display-")) {
|
| 264 | struct device_node *of_parent;
|
| 265 | const __be32 *vendor_p, *device_p;
|
| 266 |
|
| 267 |
|
| 268 | of_parent = of_get_parent(of_node);
|
| 269 | vendor_p = of_get_property(of_parent, "vendor-id", NULL);
|
| 270 | device_p = of_get_property(of_parent, "device-id", NULL);
|
| 271 | if (vendor_p && device_p) {
|
| 272 | u32 vendor = be32_to_cpup(vendor_p);
|
| 273 | u32 device = be32_to_cpup(device_p);
|
| 274 |
|
| 275 | if (is_avivo(vendor, device))
|
| 276 | model = OFDRM_MODEL_AVIVO;
|
| 277 | }
|
| 278 | of_node_put(of_parent);
|
| 279 | } else if (of_device_is_compatible(of_node, "qemu,std-vga")) {
|
| 280 | model = OFDRM_MODEL_QEMU;
|
| 281 | }
|
| 282 |
|
| 283 | return model;
|
| 284 | }
|
| 285 |
|
| 286 | |
| 287 | * Open Firmware display device
|
| 288 |
|
| 289 |
|
| 290 | struct ofdrm_device;
|
| 291 |
|
| 292 | struct ofdrm_device_funcs {
|
| 293 | void __iomem *(*cmap_ioremap)(struct ofdrm_device *odev,
|
| 294 | struct device_node *of_node,
|
| 295 | u64 fb_bas);
|
| 296 | void (*cmap_write)(struct ofdrm_device *odev, unsigned char index,
|
| 297 | unsigned char r, unsigned char g, unsigned char b);
|
| 298 | };
|
| 299 |
|
| 300 | struct ofdrm_device {
|
| 301 | struct drm_sysfb_device sysfb;
|
| 302 |
|
| 303 | const struct ofdrm_device_funcs *funcs;
|
| 304 |
|
| 305 |
|
| 306 | void __iomem *cmap_base;
|
| 307 |
|
| 308 | u8 edid[EDID_LENGTH];
|
| 309 |
|
| 310 |
|
| 311 | u32 formats[DRM_SYSFB_PLANE_NFORMATS(1)];
|
| 312 | struct drm_plane primary_plane;
|
| 313 | struct drm_crtc crtc;
|
| 314 | struct drm_encoder encoder;
|
| 315 | struct drm_connector connector;
|
| 316 | };
|
| 317 |
|
| 318 | static struct ofdrm_device *ofdrm_device_of_dev(struct drm_device *dev)
|
| 319 | {
|
| 320 | return container_of(to_drm_sysfb_device(dev), struct ofdrm_device, sysfb);
|
| 321 | }
|
| 322 |
|
| 323 | |
| 324 | * Hardware
|
| 325 |
|
| 326 |
|
| 327 | #if defined(CONFIG_PCI)
|
| 328 | static struct pci_dev *display_get_pci_dev_of(struct drm_device *dev, struct device_node *of_node)
|
| 329 | {
|
| 330 | const __be32 *vendor_p, *device_p;
|
| 331 | u32 vendor, device;
|
| 332 | struct pci_dev *pcidev;
|
| 333 |
|
| 334 | vendor_p = of_get_property(of_node, "vendor-id", NULL);
|
| 335 | if (!vendor_p)
|
| 336 | return ERR_PTR(-ENODEV);
|
| 337 | vendor = be32_to_cpup(vendor_p);
|
| 338 |
|
| 339 | device_p = of_get_property(of_node, "device-id", NULL);
|
| 340 | if (!device_p)
|
| 341 | return ERR_PTR(-ENODEV);
|
| 342 | device = be32_to_cpup(device_p);
|
| 343 |
|
| 344 | pcidev = pci_get_device(vendor, device, NULL);
|
| 345 | if (!pcidev)
|
| 346 | return ERR_PTR(-ENODEV);
|
| 347 |
|
| 348 | return pcidev;
|
| 349 | }
|
| 350 |
|
| 351 | static void ofdrm_pci_release(void *data)
|
| 352 | {
|
| 353 | struct pci_dev *pcidev = data;
|
| 354 |
|
| 355 | pci_disable_device(pcidev);
|
| 356 | pci_dev_put(pcidev);
|
| 357 | }
|
| 358 |
|
| 359 | static int ofdrm_device_init_pci(struct ofdrm_device *odev)
|
| 360 | {
|
| 361 | struct drm_device *dev = &odev->sysfb.dev;
|
| 362 | struct platform_device *pdev = to_platform_device(dev->dev);
|
| 363 | struct device_node *of_node = pdev->dev.of_node;
|
| 364 | struct pci_dev *pcidev;
|
| 365 | int ret;
|
| 366 |
|
| 367 | |
| 368 | * Never use pcim_ or other managed helpers on the returned PCI
|
| 369 | * device. Otherwise, probing the native driver will fail for
|
| 370 | * resource conflicts. PCI-device management has to be tied to
|
| 371 | * the lifetime of the platform device until the native driver
|
| 372 | * takes over.
|
| 373 |
|
| 374 | pcidev = display_get_pci_dev_of(dev, of_node);
|
| 375 | if (IS_ERR(pcidev))
|
| 376 | return 0;
|
| 377 |
|
| 378 | ret = pci_enable_device(pcidev);
|
| 379 | if (ret) {
|
| 380 | drm_err(dev, "pci_enable_device(%s) failed: %d\n",
|
| 381 | dev_name(&pcidev->dev), ret);
|
| 382 | pci_dev_put(pcidev);
|
| 383 | return ret;
|
| 384 | }
|
| 385 | ret = devm_add_action_or_reset(&pdev->dev, ofdrm_pci_release, pcidev);
|
| 386 | if (ret)
|
| 387 | return ret;
|
| 388 |
|
| 389 | return 0;
|
| 390 | }
|
| 391 | #else
|
| 392 | static int ofdrm_device_init_pci(struct ofdrm_device *odev)
|
| 393 | {
|
| 394 | return 0;
|
| 395 | }
|
| 396 | #endif
|
| 397 |
|
| 398 | |
| 399 | * OF display settings
|
| 400 |
|
| 401 |
|
| 402 | static struct resource *ofdrm_find_fb_resource(struct ofdrm_device *odev,
|
| 403 | struct resource *fb_res)
|
| 404 | {
|
| 405 | struct platform_device *pdev = to_platform_device(odev->sysfb.dev.dev);
|
| 406 | struct resource *res, *max_res = NULL;
|
| 407 | u32 i;
|
| 408 |
|
| 409 | for (i = 0; pdev->num_resources; ++i) {
|
| 410 | res = platform_get_resource(pdev, IORESOURCE_MEM, i);
|
| 411 | if (!res)
|
| 412 | break;
|
| 413 | if (resource_size(res) < resource_size(fb_res))
|
| 414 | continue;
|
| 415 | if (fb_res->start && resource_contains(res, fb_res))
|
| 416 | return res;
|
| 417 | if (!max_res || resource_size(res) > resource_size(max_res))
|
| 418 | max_res = res;
|
| 419 | }
|
| 420 |
|
| 421 | return max_res;
|
| 422 | }
|
| 423 |
|
| 424 | |
| 425 | * Colormap / Palette
|
| 426 |
|
| 427 |
|
| 428 | static void __iomem *get_cmap_address_of(struct ofdrm_device *odev, struct device_node *of_node,
|
| 429 | int bar_no, unsigned long offset, unsigned long size)
|
| 430 | {
|
| 431 | struct drm_device *dev = &odev->sysfb.dev;
|
| 432 | const __be32 *addr_p;
|
| 433 | u64 max_size, address;
|
| 434 | unsigned int flags;
|
| 435 | void __iomem *mem;
|
| 436 |
|
| 437 | addr_p = of_get_pci_address(of_node, bar_no, &max_size, &flags);
|
| 438 | if (!addr_p)
|
| 439 | addr_p = of_get_address(of_node, bar_no, &max_size, &flags);
|
| 440 | if (!addr_p)
|
| 441 | return IOMEM_ERR_PTR(-ENODEV);
|
| 442 |
|
| 443 | if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
|
| 444 | return IOMEM_ERR_PTR(-ENODEV);
|
| 445 |
|
| 446 | if ((offset + size) >= max_size)
|
| 447 | return IOMEM_ERR_PTR(-ENODEV);
|
| 448 |
|
| 449 | address = of_translate_address(of_node, addr_p);
|
| 450 | if (address == OF_BAD_ADDR)
|
| 451 | return IOMEM_ERR_PTR(-ENODEV);
|
| 452 |
|
| 453 | mem = devm_ioremap(dev->dev, address + offset, size);
|
| 454 | if (!mem)
|
| 455 | return IOMEM_ERR_PTR(-ENOMEM);
|
| 456 |
|
| 457 | return mem;
|
| 458 | }
|
| 459 |
|
| 460 | static void __iomem *ofdrm_mach64_cmap_ioremap(struct ofdrm_device *odev,
|
| 461 | struct device_node *of_node,
|
| 462 | u64 fb_base)
|
| 463 | {
|
| 464 | struct drm_device *dev = &odev->sysfb.dev;
|
| 465 | u64 address;
|
| 466 | void __iomem *cmap_base;
|
| 467 |
|
| 468 | address = fb_base & 0xff000000ul;
|
| 469 | address += 0x7ff000;
|
| 470 |
|
| 471 | cmap_base = devm_ioremap(dev->dev, address, 0x1000);
|
| 472 | if (!cmap_base)
|
| 473 | return IOMEM_ERR_PTR(-ENOMEM);
|
| 474 |
|
| 475 | return cmap_base;
|
| 476 | }
|
| 477 |
|
| 478 | static void ofdrm_mach64_cmap_write(struct ofdrm_device *odev, unsigned char index,
|
| 479 | unsigned char r, unsigned char g, unsigned char b)
|
| 480 | {
|
| 481 | void __iomem *addr = odev->cmap_base + 0xcc0;
|
| 482 | void __iomem *data = odev->cmap_base + 0xcc0 + 1;
|
| 483 |
|
| 484 | writeb(index, addr);
|
| 485 | writeb(r, data);
|
| 486 | writeb(g, data);
|
| 487 | writeb(b, data);
|
| 488 | }
|
| 489 |
|
| 490 | static void __iomem *ofdrm_rage128_cmap_ioremap(struct ofdrm_device *odev,
|
| 491 | struct device_node *of_node,
|
| 492 | u64 fb_base)
|
| 493 | {
|
| 494 | return get_cmap_address_of(odev, of_node, 2, 0, 0x1fff);
|
| 495 | }
|
| 496 |
|
| 497 | static void ofdrm_rage128_cmap_write(struct ofdrm_device *odev, unsigned char index,
|
| 498 | unsigned char r, unsigned char g, unsigned char b)
|
| 499 | {
|
| 500 | void __iomem *addr = odev->cmap_base + 0xb0;
|
| 501 | void __iomem *data = odev->cmap_base + 0xb4;
|
| 502 | u32 color = (r << 16) | (g << 8) | b;
|
| 503 |
|
| 504 | writeb(index, addr);
|
| 505 | writel(color, data);
|
| 506 | }
|
| 507 |
|
| 508 | static void __iomem *ofdrm_rage_m3a_cmap_ioremap(struct ofdrm_device *odev,
|
| 509 | struct device_node *of_node,
|
| 510 | u64 fb_base)
|
| 511 | {
|
| 512 | return get_cmap_address_of(odev, of_node, 2, 0, 0x1fff);
|
| 513 | }
|
| 514 |
|
| 515 | static void ofdrm_rage_m3a_cmap_write(struct ofdrm_device *odev, unsigned char index,
|
| 516 | unsigned char r, unsigned char g, unsigned char b)
|
| 517 | {
|
| 518 | void __iomem *dac_ctl = odev->cmap_base + 0x58;
|
| 519 | void __iomem *addr = odev->cmap_base + 0xb0;
|
| 520 | void __iomem *data = odev->cmap_base + 0xb4;
|
| 521 | u32 color = (r << 16) | (g << 8) | b;
|
| 522 | u32 val;
|
| 523 |
|
| 524 |
|
| 525 | val = readl(dac_ctl);
|
| 526 | val &= ~0x20;
|
| 527 | writel(val, dac_ctl);
|
| 528 |
|
| 529 |
|
| 530 | writeb(index, addr);
|
| 531 | writel(color, data);
|
| 532 | }
|
| 533 |
|
| 534 | static void __iomem *ofdrm_rage_m3b_cmap_ioremap(struct ofdrm_device *odev,
|
| 535 | struct device_node *of_node,
|
| 536 | u64 fb_base)
|
| 537 | {
|
| 538 | return get_cmap_address_of(odev, of_node, 2, 0, 0x1fff);
|
| 539 | }
|
| 540 |
|
| 541 | static void ofdrm_rage_m3b_cmap_write(struct ofdrm_device *odev, unsigned char index,
|
| 542 | unsigned char r, unsigned char g, unsigned char b)
|
| 543 | {
|
| 544 | void __iomem *dac_ctl = odev->cmap_base + 0x58;
|
| 545 | void __iomem *addr = odev->cmap_base + 0xb0;
|
| 546 | void __iomem *data = odev->cmap_base + 0xb4;
|
| 547 | u32 color = (r << 16) | (g << 8) | b;
|
| 548 | u32 val;
|
| 549 |
|
| 550 |
|
| 551 | val = readl(dac_ctl);
|
| 552 | val |= 0x20;
|
| 553 | writel(val, dac_ctl);
|
| 554 |
|
| 555 |
|
| 556 | writeb(index, addr);
|
| 557 | writel(color, data);
|
| 558 | }
|
| 559 |
|
| 560 | static void __iomem *ofdrm_radeon_cmap_ioremap(struct ofdrm_device *odev,
|
| 561 | struct device_node *of_node,
|
| 562 | u64 fb_base)
|
| 563 | {
|
| 564 | return get_cmap_address_of(odev, of_node, 1, 0, 0x1fff);
|
| 565 | }
|
| 566 |
|
| 567 | static void __iomem *ofdrm_gxt2000_cmap_ioremap(struct ofdrm_device *odev,
|
| 568 | struct device_node *of_node,
|
| 569 | u64 fb_base)
|
| 570 | {
|
| 571 | return get_cmap_address_of(odev, of_node, 0, 0x6000, 0x1000);
|
| 572 | }
|
| 573 |
|
| 574 | static void ofdrm_gxt2000_cmap_write(struct ofdrm_device *odev, unsigned char index,
|
| 575 | unsigned char r, unsigned char g, unsigned char b)
|
| 576 | {
|
| 577 | void __iomem *data = ((unsigned int __iomem *)odev->cmap_base) + index;
|
| 578 | u32 color = (r << 16) | (g << 8) | b;
|
| 579 |
|
| 580 | writel(color, data);
|
| 581 | }
|
| 582 |
|
| 583 | static void __iomem *ofdrm_avivo_cmap_ioremap(struct ofdrm_device *odev,
|
| 584 | struct device_node *of_node,
|
| 585 | u64 fb_base)
|
| 586 | {
|
| 587 | struct device_node *of_parent;
|
| 588 | void __iomem *cmap_base;
|
| 589 |
|
| 590 | of_parent = of_get_parent(of_node);
|
| 591 | cmap_base = get_cmap_address_of(odev, of_parent, 0, 0, 0x10000);
|
| 592 | of_node_put(of_parent);
|
| 593 |
|
| 594 | return cmap_base;
|
| 595 | }
|
| 596 |
|
| 597 | static void ofdrm_avivo_cmap_write(struct ofdrm_device *odev, unsigned char index,
|
| 598 | unsigned char r, unsigned char g, unsigned char b)
|
| 599 | {
|
| 600 | void __iomem *lutsel = odev->cmap_base + AVIVO_DC_LUT_RW_SELECT;
|
| 601 | void __iomem *addr = odev->cmap_base + AVIVO_DC_LUT_RW_INDEX;
|
| 602 | void __iomem *data = odev->cmap_base + AVIVO_DC_LUT_30_COLOR;
|
| 603 | u32 color = (r << 22) | (g << 12) | (b << 2);
|
| 604 |
|
| 605 |
|
| 606 |
|
| 607 | writel(1, lutsel);
|
| 608 | writeb(index, addr);
|
| 609 | writel(color, data);
|
| 610 |
|
| 611 | writel(0, lutsel);
|
| 612 | writeb(index, addr);
|
| 613 | writel(color, data);
|
| 614 | }
|
| 615 |
|
| 616 | static void __iomem *ofdrm_qemu_cmap_ioremap(struct ofdrm_device *odev,
|
| 617 | struct device_node *of_node,
|
| 618 | u64 fb_base)
|
| 619 | {
|
| 620 | static const __be32 io_of_addr[3] = {
|
| 621 | cpu_to_be32(0x01000000),
|
| 622 | cpu_to_be32(0x00),
|
| 623 | cpu_to_be32(0x00),
|
| 624 | };
|
| 625 |
|
| 626 | struct drm_device *dev = &odev->sysfb.dev;
|
| 627 | u64 address;
|
| 628 | void __iomem *cmap_base;
|
| 629 |
|
| 630 | address = of_translate_address(of_node, io_of_addr);
|
| 631 | if (address == OF_BAD_ADDR)
|
| 632 | return IOMEM_ERR_PTR(-ENODEV);
|
| 633 |
|
| 634 | cmap_base = devm_ioremap(dev->dev, address + 0x3c8, 2);
|
| 635 | if (!cmap_base)
|
| 636 | return IOMEM_ERR_PTR(-ENOMEM);
|
| 637 |
|
| 638 | return cmap_base;
|
| 639 | }
|
| 640 |
|
| 641 | static void ofdrm_qemu_cmap_write(struct ofdrm_device *odev, unsigned char index,
|
| 642 | unsigned char r, unsigned char g, unsigned char b)
|
| 643 | {
|
| 644 | void __iomem *addr = odev->cmap_base;
|
| 645 | void __iomem *data = odev->cmap_base + 1;
|
| 646 |
|
| 647 | writeb(index, addr);
|
| 648 | writeb(r, data);
|
| 649 | writeb(g, data);
|
| 650 | writeb(b, data);
|
| 651 | }
|
| 652 |
|
| 653 | static void ofdrm_set_gamma_lut(struct drm_crtc *crtc, unsigned int index,
|
| 654 | u16 red, u16 green, u16 blue)
|
| 655 | {
|
| 656 | struct drm_device *dev = crtc->dev;
|
| 657 | struct ofdrm_device *odev = ofdrm_device_of_dev(dev);
|
| 658 | u8 i8 = index & 0xff;
|
| 659 | u8 r8 = red >> 8;
|
| 660 | u8 g8 = green >> 8;
|
| 661 | u8 b8 = blue >> 8;
|
| 662 |
|
| 663 | if (drm_WARN_ON_ONCE(dev, index != i8))
|
| 664 | return;
|
| 665 |
|
| 666 | odev->funcs->cmap_write(odev, i8, r8, g8, b8);
|
| 667 | }
|
| 668 |
|
| 669 | static void ofdrm_device_fill_gamma(struct ofdrm_device *odev,
|
| 670 | const struct drm_format_info *format)
|
| 671 | {
|
| 672 | struct drm_device *dev = &odev->sysfb.dev;
|
| 673 | struct drm_crtc *crtc = &odev->crtc;
|
| 674 |
|
| 675 | switch (format->format) {
|
| 676 | case DRM_FORMAT_RGB565:
|
| 677 | case DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN:
|
| 678 | drm_crtc_fill_gamma_565(crtc, ofdrm_set_gamma_lut);
|
| 679 | break;
|
| 680 | case DRM_FORMAT_XRGB8888:
|
| 681 | case DRM_FORMAT_BGRX8888:
|
| 682 | drm_crtc_fill_gamma_888(crtc, ofdrm_set_gamma_lut);
|
| 683 | break;
|
| 684 | default:
|
| 685 | drm_warn_once(dev, "Unsupported format %p4cc for gamma correction\n",
|
| 686 | &format->format);
|
| 687 | break;
|
| 688 | }
|
| 689 | }
|
| 690 |
|
| 691 | static void ofdrm_device_load_gamma(struct ofdrm_device *odev,
|
| 692 | const struct drm_format_info *format,
|
| 693 | struct drm_color_lut *lut)
|
| 694 | {
|
| 695 | struct drm_device *dev = &odev->sysfb.dev;
|
| 696 | struct drm_crtc *crtc = &odev->crtc;
|
| 697 |
|
| 698 | switch (format->format) {
|
| 699 | case DRM_FORMAT_RGB565:
|
| 700 | case DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN:
|
| 701 | drm_crtc_load_gamma_565_from_888(crtc, lut, ofdrm_set_gamma_lut);
|
| 702 | break;
|
| 703 | case DRM_FORMAT_XRGB8888:
|
| 704 | case DRM_FORMAT_BGRX8888:
|
| 705 | drm_crtc_load_gamma_888(crtc, lut, ofdrm_set_gamma_lut);
|
| 706 | break;
|
| 707 | default:
|
| 708 | drm_warn_once(dev, "Unsupported format %p4cc for gamma correction\n",
|
| 709 | &format->format);
|
| 710 | break;
|
| 711 | }
|
| 712 | }
|
| 713 |
|
| 714 | |
| 715 | * Modesetting
|
| 716 |
|
| 717 |
|
| 718 | static const u64 ofdrm_primary_plane_format_modifiers[] = {
|
| 719 | DRM_SYSFB_PLANE_FORMAT_MODIFIERS,
|
| 720 | };
|
| 721 |
|
| 722 | static const struct drm_plane_helper_funcs ofdrm_primary_plane_helper_funcs = {
|
| 723 | DRM_SYSFB_PLANE_HELPER_FUNCS,
|
| 724 | };
|
| 725 |
|
| 726 | static const struct drm_plane_funcs ofdrm_primary_plane_funcs = {
|
| 727 | DRM_SYSFB_PLANE_FUNCS,
|
| 728 | .destroy = drm_plane_cleanup,
|
| 729 | };
|
| 730 |
|
| 731 | static void ofdrm_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_commit *state)
|
| 732 | {
|
| 733 | struct ofdrm_device *odev = ofdrm_device_of_dev(crtc->dev);
|
| 734 | struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
| 735 | struct drm_sysfb_crtc_state *sysfb_crtc_state = to_drm_sysfb_crtc_state(crtc_state);
|
| 736 |
|
| 737 | if (crtc_state->enable && crtc_state->color_mgmt_changed) {
|
| 738 | const struct drm_format_info *format = sysfb_crtc_state->format;
|
| 739 |
|
| 740 | if (crtc_state->gamma_lut)
|
| 741 | ofdrm_device_load_gamma(odev, format, crtc_state->gamma_lut->data);
|
| 742 | else
|
| 743 | ofdrm_device_fill_gamma(odev, format);
|
| 744 | }
|
| 745 | }
|
| 746 |
|
| 747 | static const struct drm_crtc_helper_funcs ofdrm_crtc_helper_funcs = {
|
| 748 | DRM_SYSFB_CRTC_HELPER_FUNCS,
|
| 749 | .atomic_flush = ofdrm_crtc_helper_atomic_flush,
|
| 750 | };
|
| 751 |
|
| 752 | static const struct drm_crtc_funcs ofdrm_crtc_funcs = {
|
| 753 | DRM_SYSFB_CRTC_FUNCS,
|
| 754 | .destroy = drm_crtc_cleanup,
|
| 755 | };
|
| 756 |
|
| 757 | static const struct drm_encoder_funcs ofdrm_encoder_funcs = {
|
| 758 | .destroy = drm_encoder_cleanup,
|
| 759 | };
|
| 760 |
|
| 761 | static const struct drm_connector_helper_funcs ofdrm_connector_helper_funcs = {
|
| 762 | DRM_SYSFB_CONNECTOR_HELPER_FUNCS,
|
| 763 | };
|
| 764 |
|
| 765 | static const struct drm_connector_funcs ofdrm_connector_funcs = {
|
| 766 | DRM_SYSFB_CONNECTOR_FUNCS,
|
| 767 | .destroy = drm_connector_cleanup,
|
| 768 | };
|
| 769 |
|
| 770 | static const struct drm_mode_config_funcs ofdrm_mode_config_funcs = {
|
| 771 | DRM_SYSFB_MODE_CONFIG_FUNCS,
|
| 772 | };
|
| 773 |
|
| 774 | |
| 775 | * Init / Cleanup
|
| 776 |
|
| 777 |
|
| 778 | static const struct ofdrm_device_funcs ofdrm_unknown_device_funcs = {
|
| 779 | };
|
| 780 |
|
| 781 | static const struct ofdrm_device_funcs ofdrm_mach64_device_funcs = {
|
| 782 | .cmap_ioremap = ofdrm_mach64_cmap_ioremap,
|
| 783 | .cmap_write = ofdrm_mach64_cmap_write,
|
| 784 | };
|
| 785 |
|
| 786 | static const struct ofdrm_device_funcs ofdrm_rage128_device_funcs = {
|
| 787 | .cmap_ioremap = ofdrm_rage128_cmap_ioremap,
|
| 788 | .cmap_write = ofdrm_rage128_cmap_write,
|
| 789 | };
|
| 790 |
|
| 791 | static const struct ofdrm_device_funcs ofdrm_rage_m3a_device_funcs = {
|
| 792 | .cmap_ioremap = ofdrm_rage_m3a_cmap_ioremap,
|
| 793 | .cmap_write = ofdrm_rage_m3a_cmap_write,
|
| 794 | };
|
| 795 |
|
| 796 | static const struct ofdrm_device_funcs ofdrm_rage_m3b_device_funcs = {
|
| 797 | .cmap_ioremap = ofdrm_rage_m3b_cmap_ioremap,
|
| 798 | .cmap_write = ofdrm_rage_m3b_cmap_write,
|
| 799 | };
|
| 800 |
|
| 801 | static const struct ofdrm_device_funcs ofdrm_radeon_device_funcs = {
|
| 802 | .cmap_ioremap = ofdrm_radeon_cmap_ioremap,
|
| 803 | .cmap_write = ofdrm_rage128_cmap_write,
|
| 804 | };
|
| 805 |
|
| 806 | static const struct ofdrm_device_funcs ofdrm_gxt2000_device_funcs = {
|
| 807 | .cmap_ioremap = ofdrm_gxt2000_cmap_ioremap,
|
| 808 | .cmap_write = ofdrm_gxt2000_cmap_write,
|
| 809 | };
|
| 810 |
|
| 811 | static const struct ofdrm_device_funcs ofdrm_avivo_device_funcs = {
|
| 812 | .cmap_ioremap = ofdrm_avivo_cmap_ioremap,
|
| 813 | .cmap_write = ofdrm_avivo_cmap_write,
|
| 814 | };
|
| 815 |
|
| 816 | static const struct ofdrm_device_funcs ofdrm_qemu_device_funcs = {
|
| 817 | .cmap_ioremap = ofdrm_qemu_cmap_ioremap,
|
| 818 | .cmap_write = ofdrm_qemu_cmap_write,
|
| 819 | };
|
| 820 |
|
| 821 | static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
|
| 822 | struct platform_device *pdev)
|
| 823 | {
|
| 824 | struct device_node *of_node = pdev->dev.of_node;
|
| 825 | struct ofdrm_device *odev;
|
| 826 | struct drm_sysfb_device *sysfb;
|
| 827 | struct drm_device *dev;
|
| 828 | enum ofdrm_model model;
|
| 829 | bool big_endian;
|
| 830 | int width, height, depth, linebytes;
|
| 831 | const struct drm_format_info *format;
|
| 832 | u64 address;
|
| 833 | const u8 *edid;
|
| 834 | resource_size_t fb_size, fb_base, fb_pgbase, fb_pgsize;
|
| 835 | struct resource *res, *mem;
|
| 836 | void __iomem *screen_base;
|
| 837 | struct drm_plane *primary_plane;
|
| 838 | struct drm_crtc *crtc;
|
| 839 | struct drm_encoder *encoder;
|
| 840 | struct drm_connector *connector;
|
| 841 | unsigned long max_width, max_height;
|
| 842 | size_t nformats;
|
| 843 | int ret;
|
| 844 |
|
| 845 | odev = devm_drm_dev_alloc(&pdev->dev, drv, struct ofdrm_device, sysfb.dev);
|
| 846 | if (IS_ERR(odev))
|
| 847 | return ERR_CAST(odev);
|
| 848 | sysfb = &odev->sysfb;
|
| 849 | dev = &sysfb->dev;
|
| 850 | platform_set_drvdata(pdev, dev);
|
| 851 |
|
| 852 | ret = ofdrm_device_init_pci(odev);
|
| 853 | if (ret)
|
| 854 | return ERR_PTR(ret);
|
| 855 |
|
| 856 | |
| 857 | * OF display-node settings
|
| 858 |
|
| 859 |
|
| 860 | model = display_get_model_of(dev, of_node);
|
| 861 | drm_dbg(dev, "detected model %d\n", model);
|
| 862 |
|
| 863 | switch (model) {
|
| 864 | case OFDRM_MODEL_UNKNOWN:
|
| 865 | odev->funcs = &ofdrm_unknown_device_funcs;
|
| 866 | break;
|
| 867 | case OFDRM_MODEL_MACH64:
|
| 868 | odev->funcs = &ofdrm_mach64_device_funcs;
|
| 869 | break;
|
| 870 | case OFDRM_MODEL_RAGE128:
|
| 871 | odev->funcs = &ofdrm_rage128_device_funcs;
|
| 872 | break;
|
| 873 | case OFDRM_MODEL_RAGE_M3A:
|
| 874 | odev->funcs = &ofdrm_rage_m3a_device_funcs;
|
| 875 | break;
|
| 876 | case OFDRM_MODEL_RAGE_M3B:
|
| 877 | odev->funcs = &ofdrm_rage_m3b_device_funcs;
|
| 878 | break;
|
| 879 | case OFDRM_MODEL_RADEON:
|
| 880 | odev->funcs = &ofdrm_radeon_device_funcs;
|
| 881 | break;
|
| 882 | case OFDRM_MODEL_GXT2000:
|
| 883 | odev->funcs = &ofdrm_gxt2000_device_funcs;
|
| 884 | break;
|
| 885 | case OFDRM_MODEL_AVIVO:
|
| 886 | odev->funcs = &ofdrm_avivo_device_funcs;
|
| 887 | break;
|
| 888 | case OFDRM_MODEL_QEMU:
|
| 889 | odev->funcs = &ofdrm_qemu_device_funcs;
|
| 890 | break;
|
| 891 | }
|
| 892 |
|
| 893 | big_endian = display_get_big_endian_of(dev, of_node);
|
| 894 |
|
| 895 | width = display_get_width_of(dev, of_node);
|
| 896 | if (width < 0)
|
| 897 | return ERR_PTR(width);
|
| 898 | height = display_get_height_of(dev, of_node);
|
| 899 | if (height < 0)
|
| 900 | return ERR_PTR(height);
|
| 901 | depth = display_get_depth_of(dev, of_node);
|
| 902 | if (depth < 0)
|
| 903 | return ERR_PTR(depth);
|
| 904 | linebytes = display_get_linebytes_of(dev, of_node);
|
| 905 | if (linebytes < 0)
|
| 906 | return ERR_PTR(linebytes);
|
| 907 |
|
| 908 | format = display_get_validated_format(dev, depth, big_endian);
|
| 909 | if (IS_ERR(format))
|
| 910 | return ERR_CAST(format);
|
| 911 | if (!linebytes) {
|
| 912 | linebytes = drm_format_info_min_pitch(format, 0, width);
|
| 913 | if (drm_WARN_ON(dev, !linebytes))
|
| 914 | return ERR_PTR(-EINVAL);
|
| 915 | }
|
| 916 |
|
| 917 | if (check_mul_overflow(linebytes, height, &fb_size)) {
|
| 918 | drm_err(dev, "framebuffer size exceeds maximum\n");
|
| 919 | return ERR_PTR(-EINVAL);
|
| 920 | }
|
| 921 |
|
| 922 | |
| 923 | * Try to figure out the address of the framebuffer. Unfortunately, Open
|
| 924 | * Firmware doesn't provide a standard way to do so. All we can do is a
|
| 925 | * dodgy heuristic that happens to work in practice.
|
| 926 | *
|
| 927 | * On most machines, the "address" property contains what we need, though
|
| 928 | * not on Matrox cards found in IBM machines. What appears to give good
|
| 929 | * results is to go through the PCI ranges and pick one that encloses the
|
| 930 | * "address" property. If none match, we pick the largest.
|
| 931 |
|
| 932 | address = display_get_address_of(dev, of_node);
|
| 933 | if (address != OF_BAD_ADDR) {
|
| 934 | struct resource fb_res = DEFINE_RES_MEM(address, fb_size);
|
| 935 |
|
| 936 | res = ofdrm_find_fb_resource(odev, &fb_res);
|
| 937 | if (!res)
|
| 938 | return ERR_PTR(-EINVAL);
|
| 939 | if (resource_contains(res, &fb_res))
|
| 940 | fb_base = address;
|
| 941 | else
|
| 942 | fb_base = res->start;
|
| 943 | } else {
|
| 944 | struct resource fb_res = DEFINE_RES_MEM(0u, fb_size);
|
| 945 |
|
| 946 | res = ofdrm_find_fb_resource(odev, &fb_res);
|
| 947 | if (!res)
|
| 948 | return ERR_PTR(-EINVAL);
|
| 949 | fb_base = res->start;
|
| 950 | }
|
| 951 |
|
| 952 | |
| 953 | * I/O resources
|
| 954 |
|
| 955 |
|
| 956 | fb_pgbase = round_down(fb_base, PAGE_SIZE);
|
| 957 | fb_pgsize = fb_base - fb_pgbase + round_up(fb_size, PAGE_SIZE);
|
| 958 |
|
| 959 | ret = devm_aperture_acquire_for_platform_device(pdev, fb_pgbase, fb_pgsize);
|
| 960 | if (ret) {
|
| 961 | drm_err(dev, "could not acquire memory range %pr: error %d\n", &res, ret);
|
| 962 | return ERR_PTR(ret);
|
| 963 | }
|
| 964 |
|
| 965 | mem = devm_request_mem_region(&pdev->dev, fb_pgbase, fb_pgsize, drv->name);
|
| 966 | if (!mem) {
|
| 967 | drm_warn(dev, "could not acquire memory region %pr\n", &res);
|
| 968 | return ERR_PTR(-ENOMEM);
|
| 969 | }
|
| 970 |
|
| 971 | screen_base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
|
| 972 | if (!screen_base)
|
| 973 | return ERR_PTR(-ENOMEM);
|
| 974 |
|
| 975 | if (odev->funcs->cmap_ioremap) {
|
| 976 | void __iomem *cmap_base = odev->funcs->cmap_ioremap(odev, of_node, fb_base);
|
| 977 |
|
| 978 | if (IS_ERR(cmap_base)) {
|
| 979 |
|
| 980 | drm_warn(dev, "could not find colormap: error %ld\n", PTR_ERR(cmap_base));
|
| 981 | } else {
|
| 982 | odev->cmap_base = cmap_base;
|
| 983 | }
|
| 984 | }
|
| 985 |
|
| 986 |
|
| 987 | edid = display_get_edid_of(dev, of_node, odev->edid);
|
| 988 |
|
| 989 | |
| 990 | * Firmware framebuffer
|
| 991 |
|
| 992 |
|
| 993 | iosys_map_set_vaddr_iomem(&sysfb->fb_addr, screen_base);
|
| 994 | sysfb->fb_mode = drm_sysfb_mode(width, height, 0, 0);
|
| 995 | sysfb->fb_format = format;
|
| 996 | sysfb->fb_pitch = linebytes;
|
| 997 | if (odev->cmap_base)
|
| 998 | sysfb->fb_gamma_lut_size = OFDRM_GAMMA_LUT_SIZE;
|
| 999 | sysfb->edid = edid;
|
| 1000 |
|
| 1001 | drm_dbg(dev, "display mode={" DRM_MODE_FMT "}\n", DRM_MODE_ARG(&sysfb->fb_mode));
|
| 1002 | drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, linebytes=%d byte\n",
|
| 1003 | &format->format, width, height, linebytes);
|
| 1004 |
|
| 1005 | |
| 1006 | * Mode-setting pipeline
|
| 1007 |
|
| 1008 |
|
| 1009 | ret = drmm_mode_config_init(dev);
|
| 1010 | if (ret)
|
| 1011 | return ERR_PTR(ret);
|
| 1012 |
|
| 1013 | max_width = max_t(unsigned long, width, DRM_SHADOW_PLANE_MAX_WIDTH);
|
| 1014 | max_height = max_t(unsigned long, height, DRM_SHADOW_PLANE_MAX_HEIGHT);
|
| 1015 |
|
| 1016 | dev->mode_config.min_width = width;
|
| 1017 | dev->mode_config.max_width = max_width;
|
| 1018 | dev->mode_config.min_height = height;
|
| 1019 | dev->mode_config.max_height = max_height;
|
| 1020 | dev->mode_config.funcs = &ofdrm_mode_config_funcs;
|
| 1021 | dev->mode_config.preferred_depth = format->depth;
|
| 1022 | dev->mode_config.quirk_addfb_prefer_host_byte_order = true;
|
| 1023 |
|
| 1024 |
|
| 1025 |
|
| 1026 | nformats = drm_sysfb_build_fourcc_list(dev, &format->format, 1,
|
| 1027 | odev->formats, ARRAY_SIZE(odev->formats));
|
| 1028 |
|
| 1029 | primary_plane = &odev->primary_plane;
|
| 1030 | ret = drm_universal_plane_init(dev, primary_plane, 0, &ofdrm_primary_plane_funcs,
|
| 1031 | odev->formats, nformats,
|
| 1032 | ofdrm_primary_plane_format_modifiers,
|
| 1033 | DRM_PLANE_TYPE_PRIMARY, NULL);
|
| 1034 | if (ret)
|
| 1035 | return ERR_PTR(ret);
|
| 1036 | drm_plane_helper_add(primary_plane, &ofdrm_primary_plane_helper_funcs);
|
| 1037 | drm_plane_enable_fb_damage_clips(primary_plane);
|
| 1038 |
|
| 1039 |
|
| 1040 |
|
| 1041 | crtc = &odev->crtc;
|
| 1042 | ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
|
| 1043 | &ofdrm_crtc_funcs, NULL);
|
| 1044 | if (ret)
|
| 1045 | return ERR_PTR(ret);
|
| 1046 | drm_crtc_helper_add(crtc, &ofdrm_crtc_helper_funcs);
|
| 1047 |
|
| 1048 | if (sysfb->fb_gamma_lut_size) {
|
| 1049 | ret = drm_mode_crtc_set_gamma_size(crtc, sysfb->fb_gamma_lut_size);
|
| 1050 | if (!ret)
|
| 1051 | drm_crtc_enable_color_mgmt(crtc, 0, false, sysfb->fb_gamma_lut_size);
|
| 1052 | }
|
| 1053 |
|
| 1054 |
|
| 1055 |
|
| 1056 | encoder = &odev->encoder;
|
| 1057 | ret = drm_encoder_init(dev, encoder, &ofdrm_encoder_funcs, DRM_MODE_ENCODER_NONE, NULL);
|
| 1058 | if (ret)
|
| 1059 | return ERR_PTR(ret);
|
| 1060 | encoder->possible_crtcs = drm_crtc_mask(crtc);
|
| 1061 |
|
| 1062 |
|
| 1063 |
|
| 1064 | connector = &odev->connector;
|
| 1065 | ret = drm_connector_init(dev, connector, &ofdrm_connector_funcs,
|
| 1066 | DRM_MODE_CONNECTOR_Unknown);
|
| 1067 | if (ret)
|
| 1068 | return ERR_PTR(ret);
|
| 1069 | drm_connector_helper_add(connector, &ofdrm_connector_helper_funcs);
|
| 1070 | drm_connector_set_panel_orientation_with_quirk(connector,
|
| 1071 | DRM_MODE_PANEL_ORIENTATION_UNKNOWN,
|
| 1072 | width, height);
|
| 1073 | if (edid)
|
| 1074 | drm_connector_attach_edid_property(connector);
|
| 1075 |
|
| 1076 | ret = drm_connector_attach_encoder(connector, encoder);
|
| 1077 | if (ret)
|
| 1078 | return ERR_PTR(ret);
|
| 1079 |
|
| 1080 | drm_mode_config_reset(dev);
|
| 1081 |
|
| 1082 | return odev;
|
| 1083 | }
|
| 1084 |
|
| 1085 | |
| 1086 | * DRM driver
|
| 1087 |
|
| 1088 |
|
| 1089 | DEFINE_DRM_GEM_FOPS(ofdrm_fops);
|
| 1090 |
|
| 1091 | static struct drm_driver ofdrm_driver = {
|
| 1092 | DRM_GEM_SHMEM_DRIVER_OPS,
|
| 1093 | DRM_FBDEV_SHMEM_DRIVER_OPS,
|
| 1094 | .name = DRIVER_NAME,
|
| 1095 | .desc = DRIVER_DESC,
|
| 1096 | .major = DRIVER_MAJOR,
|
| 1097 | .minor = DRIVER_MINOR,
|
| 1098 | .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET,
|
| 1099 | .fops = &ofdrm_fops,
|
| 1100 | };
|
| 1101 |
|
| 1102 | |
| 1103 | * Platform driver
|
| 1104 |
|
| 1105 |
|
| 1106 | static int ofdrm_pm_suspend(struct device *dev)
|
| 1107 | {
|
| 1108 | struct drm_device *drm = dev_get_drvdata(dev);
|
| 1109 |
|
| 1110 | return drm_mode_config_helper_suspend(drm);
|
| 1111 | }
|
| 1112 |
|
| 1113 | static int ofdrm_pm_resume(struct device *dev)
|
| 1114 | {
|
| 1115 | struct drm_device *drm = dev_get_drvdata(dev);
|
| 1116 |
|
| 1117 | return drm_mode_config_helper_resume(drm);
|
| 1118 | }
|
| 1119 |
|
| 1120 | static DEFINE_SIMPLE_DEV_PM_OPS(ofdrm_pm_ops, ofdrm_pm_suspend, ofdrm_pm_resume);
|
| 1121 |
|
| 1122 | static int ofdrm_probe(struct platform_device *pdev)
|
| 1123 | {
|
| 1124 | struct ofdrm_device *odev;
|
| 1125 | struct drm_sysfb_device *sysfb;
|
| 1126 | struct drm_device *dev;
|
| 1127 | int ret;
|
| 1128 |
|
| 1129 | odev = ofdrm_device_create(&ofdrm_driver, pdev);
|
| 1130 | if (IS_ERR(odev))
|
| 1131 | return PTR_ERR(odev);
|
| 1132 | sysfb = &odev->sysfb;
|
| 1133 | dev = &sysfb->dev;
|
| 1134 |
|
| 1135 | ret = drm_dev_register(dev, 0);
|
| 1136 | if (ret)
|
| 1137 | return ret;
|
| 1138 |
|
| 1139 | drm_client_setup(dev, sysfb->fb_format);
|
| 1140 |
|
| 1141 | return 0;
|
| 1142 | }
|
| 1143 |
|
| 1144 | static void ofdrm_remove(struct platform_device *pdev)
|
| 1145 | {
|
| 1146 | struct drm_device *dev = platform_get_drvdata(pdev);
|
| 1147 |
|
| 1148 | drm_dev_unplug(dev);
|
| 1149 | }
|
| 1150 |
|
| 1151 | static const struct of_device_id ofdrm_of_match_display[] = {
|
| 1152 | { .compatible = "display", },
|
| 1153 | { },
|
| 1154 | };
|
| 1155 | MODULE_DEVICE_TABLE(of, ofdrm_of_match_display);
|
| 1156 |
|
| 1157 | static struct platform_driver ofdrm_platform_driver = {
|
| 1158 | .driver = {
|
| 1159 | .name = "of-display",
|
| 1160 | .of_match_table = ofdrm_of_match_display,
|
| 1161 | .pm = pm_sleep_ptr(&ofdrm_pm_ops),
|
| 1162 | },
|
| 1163 | .probe = ofdrm_probe,
|
| 1164 | .remove = ofdrm_remove,
|
| 1165 | };
|
| 1166 |
|
| 1167 | module_platform_driver(ofdrm_platform_driver);
|
| 1168 |
|
| 1169 | MODULE_DESCRIPTION(DRIVER_DESC);
|
| 1170 | MODULE_LICENSE("GPL");
|