1/* 2 * i.MX IPUv3 Graphics driver 3 * 4 * Copyright (C) 2011 Sascha Hauer, Pengutronix 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 2 9 * of the License, or (at your option) any later version. 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 */ 15#include <linux/component.h> 16#include <linux/module.h> 17#include <linux/export.h> 18#include <linux/device.h> 19#include <linux/platform_device.h> 20#include <drm/drmP.h> 21#include <drm/drm_crtc_helper.h> 22#include <linux/fb.h> 23#include <linux/clk.h> 24#include <linux/errno.h> 25#include <drm/drm_gem_cma_helper.h> 26#include <drm/drm_fb_cma_helper.h> 27 28#include <video/imx-ipu-v3.h> 29#include "imx-drm.h" 30#include "ipuv3-plane.h" 31 32#define DRIVER_DESC "i.MX IPUv3 Graphics" 33 34struct ipu_crtc { 35 struct device *dev; 36 struct drm_crtc base; 37 struct imx_drm_crtc *imx_crtc; 38 39 /* plane[0] is the full plane, plane[1] is the partial plane */ 40 struct ipu_plane *plane[2]; 41 42 struct ipu_dc *dc; 43 struct ipu_di *di; 44 int enabled; 45 struct drm_pending_vblank_event *page_flip_event; 46 struct drm_framebuffer *newfb; 47 int irq; 48 u32 bus_format; 49 int di_hsync_pin; 50 int di_vsync_pin; 51}; 52 53#define to_ipu_crtc(x) container_of(x, struct ipu_crtc, base) 54 55static void ipu_fb_enable(struct ipu_crtc *ipu_crtc) 56{ 57 struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); 58 59 if (ipu_crtc->enabled) 60 return; 61 62 ipu_dc_enable(ipu); 63 ipu_plane_enable(ipu_crtc->plane[0]); 64 /* Start DC channel and DI after IDMAC */ 65 ipu_dc_enable_channel(ipu_crtc->dc); 66 ipu_di_enable(ipu_crtc->di); 67 68 ipu_crtc->enabled = 1; 69} 70 71static void ipu_fb_disable(struct ipu_crtc *ipu_crtc) 72{ 73 struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); 74 75 if (!ipu_crtc->enabled) 76 return; 77 78 /* Stop DC channel and DI before IDMAC */ 79 ipu_dc_disable_channel(ipu_crtc->dc); 80 ipu_di_disable(ipu_crtc->di); 81 ipu_plane_disable(ipu_crtc->plane[0]); 82 ipu_dc_disable(ipu); 83 84 ipu_crtc->enabled = 0; 85} 86 87static void ipu_crtc_dpms(struct drm_crtc *crtc, int mode) 88{ 89 struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); 90 91 dev_dbg(ipu_crtc->dev, "%s mode: %d\n", __func__, mode); 92 93 switch (mode) { 94 case DRM_MODE_DPMS_ON: 95 ipu_fb_enable(ipu_crtc); 96 break; 97 case DRM_MODE_DPMS_STANDBY: 98 case DRM_MODE_DPMS_SUSPEND: 99 case DRM_MODE_DPMS_OFF: 100 ipu_fb_disable(ipu_crtc); 101 break; 102 } 103} 104 105static int ipu_page_flip(struct drm_crtc *crtc, 106 struct drm_framebuffer *fb, 107 struct drm_pending_vblank_event *event, 108 uint32_t page_flip_flags) 109{ 110 struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); 111 int ret; 112 113 if (ipu_crtc->newfb) 114 return -EBUSY; 115 116 ret = imx_drm_crtc_vblank_get(ipu_crtc->imx_crtc); 117 if (ret) { 118 dev_dbg(ipu_crtc->dev, "failed to acquire vblank counter\n"); 119 list_del(&event->base.link); 120 121 return ret; 122 } 123 124 ipu_crtc->newfb = fb; 125 ipu_crtc->page_flip_event = event; 126 crtc->primary->fb = fb; 127 128 return 0; 129} 130 131static const struct drm_crtc_funcs ipu_crtc_funcs = { 132 .set_config = drm_crtc_helper_set_config, 133 .destroy = drm_crtc_cleanup, 134 .page_flip = ipu_page_flip, 135}; 136 137static int ipu_crtc_mode_set(struct drm_crtc *crtc, 138 struct drm_display_mode *orig_mode, 139 struct drm_display_mode *mode, 140 int x, int y, 141 struct drm_framebuffer *old_fb) 142{ 143 struct drm_device *dev = crtc->dev; 144 struct drm_encoder *encoder; 145 struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); 146 struct ipu_di_signal_cfg sig_cfg = {}; 147 unsigned long encoder_types = 0; 148 int ret; 149 150 dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__, 151 mode->hdisplay); 152 dev_dbg(ipu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__, 153 mode->vdisplay); 154 155 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) 156 if (encoder->crtc == crtc) 157 encoder_types |= BIT(encoder->encoder_type); 158 159 dev_dbg(ipu_crtc->dev, "%s: attached to encoder types 0x%lx\n", 160 __func__, encoder_types); 161 162 /* 163 * If we have DAC or LDB, then we need the IPU DI clock to be 164 * the same as the LDB DI clock. For TVDAC, derive the IPU DI 165 * clock from 27 MHz TVE_DI clock, but allow to divide it. 166 */ 167 if (encoder_types & (BIT(DRM_MODE_ENCODER_DAC) | 168 BIT(DRM_MODE_ENCODER_LVDS))) 169 sig_cfg.clkflags = IPU_DI_CLKMODE_SYNC | IPU_DI_CLKMODE_EXT; 170 else if (encoder_types & BIT(DRM_MODE_ENCODER_TVDAC)) 171 sig_cfg.clkflags = IPU_DI_CLKMODE_EXT; 172 else 173 sig_cfg.clkflags = 0; 174 175 sig_cfg.enable_pol = 1; 176 sig_cfg.clk_pol = 0; 177 sig_cfg.bus_format = ipu_crtc->bus_format; 178 sig_cfg.v_to_h_sync = 0; 179 sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin; 180 sig_cfg.vsync_pin = ipu_crtc->di_vsync_pin; 181 182 drm_display_mode_to_videomode(mode, &sig_cfg.mode); 183 184 ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, 185 mode->flags & DRM_MODE_FLAG_INTERLACE, 186 ipu_crtc->bus_format, mode->hdisplay); 187 if (ret) { 188 dev_err(ipu_crtc->dev, 189 "initializing display controller failed with %d\n", 190 ret); 191 return ret; 192 } 193 194 ret = ipu_di_init_sync_panel(ipu_crtc->di, &sig_cfg); 195 if (ret) { 196 dev_err(ipu_crtc->dev, 197 "initializing panel failed with %d\n", ret); 198 return ret; 199 } 200 201 return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode, 202 crtc->primary->fb, 203 0, 0, mode->hdisplay, mode->vdisplay, 204 x, y, mode->hdisplay, mode->vdisplay, 205 mode->flags & DRM_MODE_FLAG_INTERLACE); 206} 207 208static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc) 209{ 210 unsigned long flags; 211 struct drm_device *drm = ipu_crtc->base.dev; 212 213 spin_lock_irqsave(&drm->event_lock, flags); 214 if (ipu_crtc->page_flip_event) 215 drm_send_vblank_event(drm, -1, ipu_crtc->page_flip_event); 216 ipu_crtc->page_flip_event = NULL; 217 imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc); 218 spin_unlock_irqrestore(&drm->event_lock, flags); 219} 220 221static irqreturn_t ipu_irq_handler(int irq, void *dev_id) 222{ 223 struct ipu_crtc *ipu_crtc = dev_id; 224 225 imx_drm_handle_vblank(ipu_crtc->imx_crtc); 226 227 if (ipu_crtc->newfb) { 228 struct ipu_plane *plane = ipu_crtc->plane[0]; 229 230 ipu_crtc->newfb = NULL; 231 ipu_plane_set_base(plane, ipu_crtc->base.primary->fb, 232 plane->x, plane->y); 233 ipu_crtc_handle_pageflip(ipu_crtc); 234 } 235 236 return IRQ_HANDLED; 237} 238 239static bool ipu_crtc_mode_fixup(struct drm_crtc *crtc, 240 const struct drm_display_mode *mode, 241 struct drm_display_mode *adjusted_mode) 242{ 243 struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); 244 struct videomode vm; 245 int ret; 246 247 drm_display_mode_to_videomode(adjusted_mode, &vm); 248 249 ret = ipu_di_adjust_videomode(ipu_crtc->di, &vm); 250 if (ret) 251 return false; 252 253 drm_display_mode_from_videomode(&vm, adjusted_mode); 254 255 return true; 256} 257 258static void ipu_crtc_prepare(struct drm_crtc *crtc) 259{ 260 struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); 261 262 ipu_fb_disable(ipu_crtc); 263} 264 265static void ipu_crtc_commit(struct drm_crtc *crtc) 266{ 267 struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); 268 269 ipu_fb_enable(ipu_crtc); 270} 271 272static struct drm_crtc_helper_funcs ipu_helper_funcs = { 273 .dpms = ipu_crtc_dpms, 274 .mode_fixup = ipu_crtc_mode_fixup, 275 .mode_set = ipu_crtc_mode_set, 276 .prepare = ipu_crtc_prepare, 277 .commit = ipu_crtc_commit, 278}; 279 280static int ipu_enable_vblank(struct drm_crtc *crtc) 281{ 282 return 0; 283} 284 285static void ipu_disable_vblank(struct drm_crtc *crtc) 286{ 287 struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); 288 289 ipu_crtc->page_flip_event = NULL; 290 ipu_crtc->newfb = NULL; 291} 292 293static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, 294 u32 bus_format, int hsync_pin, int vsync_pin) 295{ 296 struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); 297 298 ipu_crtc->bus_format = bus_format; 299 ipu_crtc->di_hsync_pin = hsync_pin; 300 ipu_crtc->di_vsync_pin = vsync_pin; 301 302 return 0; 303} 304 305static const struct imx_drm_crtc_helper_funcs ipu_crtc_helper_funcs = { 306 .enable_vblank = ipu_enable_vblank, 307 .disable_vblank = ipu_disable_vblank, 308 .set_interface_pix_fmt = ipu_set_interface_pix_fmt, 309 .crtc_funcs = &ipu_crtc_funcs, 310 .crtc_helper_funcs = &ipu_helper_funcs, 311}; 312 313static void ipu_put_resources(struct ipu_crtc *ipu_crtc) 314{ 315 if (!IS_ERR_OR_NULL(ipu_crtc->dc)) 316 ipu_dc_put(ipu_crtc->dc); 317 if (!IS_ERR_OR_NULL(ipu_crtc->di)) 318 ipu_di_put(ipu_crtc->di); 319} 320 321static int ipu_get_resources(struct ipu_crtc *ipu_crtc, 322 struct ipu_client_platformdata *pdata) 323{ 324 struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); 325 int ret; 326 327 ipu_crtc->dc = ipu_dc_get(ipu, pdata->dc); 328 if (IS_ERR(ipu_crtc->dc)) { 329 ret = PTR_ERR(ipu_crtc->dc); 330 goto err_out; 331 } 332 333 ipu_crtc->di = ipu_di_get(ipu, pdata->di); 334 if (IS_ERR(ipu_crtc->di)) { 335 ret = PTR_ERR(ipu_crtc->di); 336 goto err_out; 337 } 338 339 return 0; 340err_out: 341 ipu_put_resources(ipu_crtc); 342 343 return ret; 344} 345 346static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, 347 struct ipu_client_platformdata *pdata, struct drm_device *drm) 348{ 349 struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); 350 int dp = -EINVAL; 351 int ret; 352 int id; 353 354 ret = ipu_get_resources(ipu_crtc, pdata); 355 if (ret) { 356 dev_err(ipu_crtc->dev, "getting resources failed with %d.\n", 357 ret); 358 return ret; 359 } 360 361 ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc, 362 &ipu_crtc_helper_funcs, ipu_crtc->dev->of_node); 363 if (ret) { 364 dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret); 365 goto err_put_resources; 366 } 367 368 if (pdata->dp >= 0) 369 dp = IPU_DP_FLOW_SYNC_BG; 370 id = imx_drm_crtc_id(ipu_crtc->imx_crtc); 371 ipu_crtc->plane[0] = ipu_plane_init(ipu_crtc->base.dev, ipu, 372 pdata->dma[0], dp, BIT(id), true); 373 ret = ipu_plane_get_resources(ipu_crtc->plane[0]); 374 if (ret) { 375 dev_err(ipu_crtc->dev, "getting plane 0 resources failed with %d.\n", 376 ret); 377 goto err_remove_crtc; 378 } 379 380 /* If this crtc is using the DP, add an overlay plane */ 381 if (pdata->dp >= 0 && pdata->dma[1] > 0) { 382 ipu_crtc->plane[1] = ipu_plane_init(ipu_crtc->base.dev, ipu, 383 pdata->dma[1], 384 IPU_DP_FLOW_SYNC_FG, 385 BIT(id), false); 386 if (IS_ERR(ipu_crtc->plane[1])) 387 ipu_crtc->plane[1] = NULL; 388 } 389 390 ipu_crtc->irq = ipu_plane_irq(ipu_crtc->plane[0]); 391 ret = devm_request_irq(ipu_crtc->dev, ipu_crtc->irq, ipu_irq_handler, 0, 392 "imx_drm", ipu_crtc); 393 if (ret < 0) { 394 dev_err(ipu_crtc->dev, "irq request failed with %d.\n", ret); 395 goto err_put_plane_res; 396 } 397 398 return 0; 399 400err_put_plane_res: 401 ipu_plane_put_resources(ipu_crtc->plane[0]); 402err_remove_crtc: 403 imx_drm_remove_crtc(ipu_crtc->imx_crtc); 404err_put_resources: 405 ipu_put_resources(ipu_crtc); 406 407 return ret; 408} 409 410static struct device_node *ipu_drm_get_port_by_id(struct device_node *parent, 411 int port_id) 412{ 413 struct device_node *port; 414 int id, ret; 415 416 port = of_get_child_by_name(parent, "port"); 417 while (port) { 418 ret = of_property_read_u32(port, "reg", &id); 419 if (!ret && id == port_id) 420 return port; 421 422 do { 423 port = of_get_next_child(parent, port); 424 if (!port) 425 return NULL; 426 } while (of_node_cmp(port->name, "port")); 427 } 428 429 return NULL; 430} 431 432static int ipu_drm_bind(struct device *dev, struct device *master, void *data) 433{ 434 struct ipu_client_platformdata *pdata = dev->platform_data; 435 struct drm_device *drm = data; 436 struct ipu_crtc *ipu_crtc; 437 int ret; 438 439 ipu_crtc = devm_kzalloc(dev, sizeof(*ipu_crtc), GFP_KERNEL); 440 if (!ipu_crtc) 441 return -ENOMEM; 442 443 ipu_crtc->dev = dev; 444 445 ret = ipu_crtc_init(ipu_crtc, pdata, drm); 446 if (ret) 447 return ret; 448 449 dev_set_drvdata(dev, ipu_crtc); 450 451 return 0; 452} 453 454static void ipu_drm_unbind(struct device *dev, struct device *master, 455 void *data) 456{ 457 struct ipu_crtc *ipu_crtc = dev_get_drvdata(dev); 458 459 imx_drm_remove_crtc(ipu_crtc->imx_crtc); 460 461 ipu_plane_put_resources(ipu_crtc->plane[0]); 462 ipu_put_resources(ipu_crtc); 463} 464 465static const struct component_ops ipu_crtc_ops = { 466 .bind = ipu_drm_bind, 467 .unbind = ipu_drm_unbind, 468}; 469 470static int ipu_drm_probe(struct platform_device *pdev) 471{ 472 struct device *dev = &pdev->dev; 473 struct ipu_client_platformdata *pdata = dev->platform_data; 474 int ret; 475 476 if (!dev->platform_data) 477 return -EINVAL; 478 479 if (!dev->of_node) { 480 /* Associate crtc device with the corresponding DI port node */ 481 dev->of_node = ipu_drm_get_port_by_id(dev->parent->of_node, 482 pdata->di + 2); 483 if (!dev->of_node) { 484 dev_err(dev, "missing port@%d node in %s\n", 485 pdata->di + 2, dev->parent->of_node->full_name); 486 return -ENODEV; 487 } 488 } 489 490 ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); 491 if (ret) 492 return ret; 493 494 return component_add(dev, &ipu_crtc_ops); 495} 496 497static int ipu_drm_remove(struct platform_device *pdev) 498{ 499 component_del(&pdev->dev, &ipu_crtc_ops); 500 return 0; 501} 502 503static struct platform_driver ipu_drm_driver = { 504 .driver = { 505 .name = "imx-ipuv3-crtc", 506 }, 507 .probe = ipu_drm_probe, 508 .remove = ipu_drm_remove, 509}; 510module_platform_driver(ipu_drm_driver); 511 512MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); 513MODULE_DESCRIPTION(DRIVER_DESC); 514MODULE_LICENSE("GPL"); 515MODULE_ALIAS("platform:imx-ipuv3-crtc"); 516