| @@ -9,12 +9,16 @@ · 8 unmodified lines |
| 9 | 9 | |
| 10 | 10 | #include <linux/clk.h> |
| 11 | 11 | #include <linux/media-bus-format.h> |
| 12 | +#include <linux/of.h> |
| 13 | +#include <linux/of_graph.h> |
| 12 | 14 | #include <linux/pm_runtime.h> |
| 13 | 15 | |
| 14 | 16 | #include <drm/drm_atomic.h> |
| 15 | 17 | #include <drm/drm_atomic_helper.h> |
| 16 | 18 | #include <drm/drm_atomic_state_helper.h> |
| 17 | 19 | #include <drm/drm_atomic_uapi.h> |
| 20 | +#include <drm/drm_bridge.h> |
| 21 | +#include <drm/drm_bridge_connector.h> |
| 18 | 22 | #include <drm/drm_crtc.h> |
| 19 | 23 | #include <drm/drm_crtc_helper.h> |
| 20 | 24 | #include <drm/drm_fb_dma_helper.h> |
| @@ -23,6 +27,7 @@ · 2 unmodified lines |
| 23 | 27 | #include <drm/drm_gem_dma_helper.h> |
| 24 | 28 | #include <drm/drm_modeset_helper.h> |
| 25 | 29 | #include <drm/drm_modeset_helper_vtables.h> |
| 30 | +#include <drm/drm_panel.h> |
| 26 | 31 | #include <drm/drm_probe_helper.h> |
| 27 | 32 | #include <drm/drm_simple_kms_helper.h> |
| 28 | 33 | #include <drm/drm_vblank.h> |
| @@ -35,10 +40,6 @@ · 6 unmodified lines |
| 35 | 40 | #include "shmob_drm_plane.h" |
| 36 | 41 | #include "shmob_drm_regs.h" |
| 37 | 42 | |
| 38 | | −/* |
| 39 | | − * TODO: panel support |
| 40 | | − */ |
| 41 | | − |
| 42 | 43 | /* ----------------------------------------------------------------------------- |
| 43 | 44 | * Page Flip |
| 44 | 45 | */ |
| @@ -201,7 +202,7 @@ static void shmob_drm_crtc_atomic_enable(struct drm_crtc *crtc, · 156 unmodified lines |
| 201 | 202 | { |
| 202 | 203 | struct shmob_drm_crtc *scrtc = to_shmob_crtc(crtc); |
| 203 | 204 | struct shmob_drm_device *sdev = to_shmob_device(crtc->dev); |
| 204 | | − const struct shmob_drm_interface_data *idata = &sdev->pdata->iface; |
| 205 | + unsigned int clk_div = sdev->config.clk_div; |
| 205 | 206 | struct device *dev = sdev->dev; |
| 206 | 207 | u32 value; |
| 207 | 208 | int ret; |
| @@ -223,17 +224,17 @@ static void shmob_drm_crtc_atomic_enable(struct drm_crtc *crtc, · 15 unmodified lines |
| 223 | 224 | lcdc_write(sdev, LDPMR, 0); |
| 224 | 225 | |
| 225 | 226 | value = sdev->lddckr; |
| 226 | | − if (idata->clk_div) { |
| 227 | + if (clk_div) { |
| 227 | 228 | /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider |
| 228 | 229 | * denominator. |
| 229 | 230 | */ |
| 230 | 231 | lcdc_write(sdev, LDDCKPAT1R, 0); |
| 231 | | − lcdc_write(sdev, LDDCKPAT2R, (1 << (idata->clk_div / 2)) - 1); |
| 232 | + lcdc_write(sdev, LDDCKPAT2R, (1 << (clk_div / 2)) - 1); |
| 232 | 233 | |
| 233 | | − if (idata->clk_div == 1) |
| 234 | + if (clk_div == 1) |
| 234 | 235 | value |= LDDCKR_MOSEL; |
| 235 | 236 | else |
| 236 | | − value |= idata->clk_div; |
| 237 | + value |= clk_div; |
| 237 | 238 | } |
| 238 | 239 | |
| 239 | 240 | lcdc_write(sdev, LDDCKR, value); |
| @@ -406,7 +407,7 @@ int shmob_drm_crtc_create(struct shmob_drm_device *sdev) · 166 unmodified lines |
| 406 | 407 | } |
| 407 | 408 | |
| 408 | 409 | /* ----------------------------------------------------------------------------- |
| 409 | | − * Encoder |
| 410 | + * Legacy Encoder |
| 410 | 411 | */ |
| 411 | 412 | |
| 412 | 413 | static bool shmob_drm_encoder_mode_fixup(struct drm_encoder *encoder, |
| @@ -435,9 +436,14 @@ static const struct drm_encoder_helper_funcs encoder_helper_funcs = { · 22 unmodified lines |
| 435 | 436 | .mode_fixup = shmob_drm_encoder_mode_fixup, |
| 436 | 437 | }; |
| 437 | 438 | |
| 439 | +/* ----------------------------------------------------------------------------- |
| 440 | + * Encoder |
| 441 | + */ |
| 442 | + |
| 438 | 443 | int shmob_drm_encoder_create(struct shmob_drm_device *sdev) |
| 439 | 444 | { |
| 440 | 445 | struct drm_encoder *encoder = &sdev->encoder; |
| 446 | + struct drm_bridge *bridge; |
| 441 | 447 | int ret; |
| 442 | 448 | |
| 443 | 449 | encoder->possible_crtcs = 1; |
| @@ -447,13 +453,30 @@ int shmob_drm_encoder_create(struct shmob_drm_device *sdev) · 3 unmodified lines |
| 447 | 453 | if (ret < 0) |
| 448 | 454 | return ret; |
| 449 | 455 | |
| 450 | | − drm_encoder_helper_add(encoder, &encoder_helper_funcs); |
| 456 | + if (sdev->pdata) { |
| 457 | + drm_encoder_helper_add(encoder, &encoder_helper_funcs); |
| 458 | + return 0; |
| 459 | + } |
| 460 | + |
| 461 | + /* Create a panel bridge */ |
| 462 | + bridge = devm_drm_of_get_bridge(sdev->dev, sdev->dev->of_node, 0, 0); |
| 463 | + if (IS_ERR(bridge)) |
| 464 | + return PTR_ERR(bridge); |
| 465 | + |
| 466 | + /* Attach the bridge to the encoder */ |
| 467 | + ret = drm_bridge_attach(encoder, bridge, NULL, |
| 468 | + DRM_BRIDGE_ATTACH_NO_CONNECTOR); |
| 469 | + if (ret) { |
| 470 | + dev_err(sdev->dev, "failed to attach bridge: %pe\n", |
| 471 | + ERR_PTR(ret)); |
| 472 | + return ret; |
| 473 | + } |
| 451 | 474 | |
| 452 | 475 | return 0; |
| 453 | 476 | } |
| 454 | 477 | |
| 455 | 478 | /* ----------------------------------------------------------------------------- |
| 456 | | − * Connector |
| 479 | + * Legacy Connector |
| 457 | 480 | */ |
| 458 | 481 | |
| 459 | 482 | static inline struct shmob_drm_connector *to_shmob_connector(struct drm_connector *connector) |
| @@ -563,13 +586,20 @@ shmob_drm_connector_init(struct shmob_drm_device *sdev, · 103 unmodified lines |
| 563 | 586 | return connector; |
| 564 | 587 | } |
| 565 | 588 | |
| 589 | +/* ----------------------------------------------------------------------------- |
| 590 | + * Connector |
| 591 | + */ |
| 592 | + |
| 566 | 593 | int shmob_drm_connector_create(struct shmob_drm_device *sdev, |
| 567 | 594 | struct drm_encoder *encoder) |
| 568 | 595 | { |
| 569 | 596 | struct drm_connector *connector; |
| 570 | 597 | int ret; |
| 571 | 598 | |
| 572 | | − connector = shmob_drm_connector_init(sdev, encoder); |
| 599 | + if (sdev->pdata) |
| 600 | + connector = shmob_drm_connector_init(sdev, encoder); |
| 601 | + else |
| 602 | + connector = drm_bridge_connector_init(&sdev->ddev, encoder); |
| 573 | 603 | if (IS_ERR(connector)) { |
| 574 | 604 | dev_err(sdev->dev, "failed to created connector: %pe\n", |
| 575 | 605 | connector); |