0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/clk.h>
0012 #include <linux/io.h>
0013 #include <linux/iopoll.h>
0014 #include <linux/media-bus-format.h>
0015 #include <linux/pm_runtime.h>
0016 #include <linux/spinlock.h>
0017
0018 #include <drm/drm_atomic.h>
0019 #include <drm/drm_atomic_helper.h>
0020 #include <drm/drm_bridge.h>
0021 #include <drm/drm_crtc.h>
0022 #include <drm/drm_encoder.h>
0023 #include <drm/drm_fb_cma_helper.h>
0024 #include <drm/drm_fourcc.h>
0025 #include <drm/drm_framebuffer.h>
0026 #include <drm/drm_gem_atomic_helper.h>
0027 #include <drm/drm_gem_cma_helper.h>
0028 #include <drm/drm_plane.h>
0029 #include <drm/drm_plane_helper.h>
0030 #include <drm/drm_vblank.h>
0031
0032 #include "mxsfb_drv.h"
0033 #include "mxsfb_regs.h"
0034
0035
0036 #define RESET_TIMEOUT 1000000
0037
0038
0039
0040
0041
0042 static u32 set_hsync_pulse_width(struct mxsfb_drm_private *mxsfb, u32 val)
0043 {
0044 return (val & mxsfb->devdata->hs_wdth_mask) <<
0045 mxsfb->devdata->hs_wdth_shift;
0046 }
0047
0048
0049
0050
0051
0052 static void mxsfb_set_formats(struct mxsfb_drm_private *mxsfb,
0053 const u32 bus_format)
0054 {
0055 struct drm_device *drm = mxsfb->drm;
0056 const u32 format = mxsfb->crtc.primary->state->fb->format->format;
0057 u32 ctrl, ctrl1;
0058
0059 DRM_DEV_DEBUG_DRIVER(drm->dev, "Using bus_format: 0x%08X\n",
0060 bus_format);
0061
0062 ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER;
0063
0064
0065 ctrl1 = readl(mxsfb->base + LCDC_CTRL1);
0066 ctrl1 &= CTRL1_CUR_FRAME_DONE_IRQ_EN | CTRL1_CUR_FRAME_DONE_IRQ;
0067
0068 switch (format) {
0069 case DRM_FORMAT_RGB565:
0070 dev_dbg(drm->dev, "Setting up RGB565 mode\n");
0071 ctrl |= CTRL_WORD_LENGTH_16;
0072 ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf);
0073 break;
0074 case DRM_FORMAT_XRGB8888:
0075 dev_dbg(drm->dev, "Setting up XRGB8888 mode\n");
0076 ctrl |= CTRL_WORD_LENGTH_24;
0077
0078 ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0x7);
0079 break;
0080 }
0081
0082 switch (bus_format) {
0083 case MEDIA_BUS_FMT_RGB565_1X16:
0084 ctrl |= CTRL_BUS_WIDTH_16;
0085 break;
0086 case MEDIA_BUS_FMT_RGB666_1X18:
0087 ctrl |= CTRL_BUS_WIDTH_18;
0088 break;
0089 case MEDIA_BUS_FMT_RGB888_1X24:
0090 ctrl |= CTRL_BUS_WIDTH_24;
0091 break;
0092 default:
0093 dev_err(drm->dev, "Unknown media bus format 0x%x\n", bus_format);
0094 break;
0095 }
0096
0097 writel(ctrl1, mxsfb->base + LCDC_CTRL1);
0098 writel(ctrl, mxsfb->base + LCDC_CTRL);
0099 }
0100
0101 static void mxsfb_set_mode(struct mxsfb_drm_private *mxsfb, u32 bus_flags)
0102 {
0103 struct drm_display_mode *m = &mxsfb->crtc.state->adjusted_mode;
0104 u32 vdctrl0, vsync_pulse_len, hsync_pulse_len;
0105
0106 writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) |
0107 TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay),
0108 mxsfb->base + mxsfb->devdata->transfer_count);
0109
0110 vsync_pulse_len = m->crtc_vsync_end - m->crtc_vsync_start;
0111
0112 vdctrl0 = VDCTRL0_ENABLE_PRESENT |
0113 VDCTRL0_VSYNC_PERIOD_UNIT |
0114 VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
0115 VDCTRL0_SET_VSYNC_PULSE_WIDTH(vsync_pulse_len);
0116 if (m->flags & DRM_MODE_FLAG_PHSYNC)
0117 vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH;
0118 if (m->flags & DRM_MODE_FLAG_PVSYNC)
0119 vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH;
0120
0121 if (!(bus_flags & DRM_BUS_FLAG_DE_LOW))
0122 vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH;
0123
0124
0125
0126
0127
0128
0129 if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE)
0130 vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING;
0131
0132 writel(vdctrl0, mxsfb->base + LCDC_VDCTRL0);
0133
0134
0135 writel(m->crtc_vtotal, mxsfb->base + LCDC_VDCTRL1);
0136
0137
0138 hsync_pulse_len = m->crtc_hsync_end - m->crtc_hsync_start;
0139 writel(set_hsync_pulse_width(mxsfb, hsync_pulse_len) |
0140 VDCTRL2_SET_HSYNC_PERIOD(m->crtc_htotal),
0141 mxsfb->base + LCDC_VDCTRL2);
0142
0143 writel(SET_HOR_WAIT_CNT(m->crtc_htotal - m->crtc_hsync_start) |
0144 SET_VERT_WAIT_CNT(m->crtc_vtotal - m->crtc_vsync_start),
0145 mxsfb->base + LCDC_VDCTRL3);
0146
0147 writel(SET_DOTCLK_H_VALID_DATA_CNT(m->hdisplay),
0148 mxsfb->base + LCDC_VDCTRL4);
0149
0150 }
0151
0152 static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb)
0153 {
0154 u32 reg;
0155
0156 if (mxsfb->clk_disp_axi)
0157 clk_prepare_enable(mxsfb->clk_disp_axi);
0158 clk_prepare_enable(mxsfb->clk);
0159
0160
0161 if (mxsfb->devdata->has_ctrl2) {
0162 reg = readl(mxsfb->base + LCDC_V4_CTRL2);
0163 reg &= ~CTRL2_SET_OUTSTANDING_REQS_MASK;
0164 reg |= CTRL2_SET_OUTSTANDING_REQS_16;
0165 writel(reg, mxsfb->base + LCDC_V4_CTRL2);
0166 }
0167
0168
0169 writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET);
0170
0171
0172 reg = readl(mxsfb->base + LCDC_VDCTRL4);
0173 reg |= VDCTRL4_SYNC_SIGNALS_ON;
0174 writel(reg, mxsfb->base + LCDC_VDCTRL4);
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201 reg = readl(mxsfb->base + LCDC_CTRL1);
0202 reg |= CTRL1_RECOVER_ON_UNDERFLOW;
0203 writel(reg, mxsfb->base + LCDC_CTRL1);
0204
0205 writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_SET);
0206 }
0207
0208 static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb)
0209 {
0210 u32 reg;
0211
0212
0213
0214
0215
0216 writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_CLR);
0217
0218 readl_poll_timeout(mxsfb->base + LCDC_CTRL, reg, !(reg & CTRL_RUN),
0219 0, 1000);
0220
0221 reg = readl(mxsfb->base + LCDC_VDCTRL4);
0222 reg &= ~VDCTRL4_SYNC_SIGNALS_ON;
0223 writel(reg, mxsfb->base + LCDC_VDCTRL4);
0224
0225 clk_disable_unprepare(mxsfb->clk);
0226 if (mxsfb->clk_disp_axi)
0227 clk_disable_unprepare(mxsfb->clk_disp_axi);
0228 }
0229
0230
0231
0232
0233
0234
0235 static int clear_poll_bit(void __iomem *addr, u32 mask)
0236 {
0237 u32 reg;
0238
0239 writel(mask, addr + REG_CLR);
0240 return readl_poll_timeout(addr, reg, !(reg & mask), 0, RESET_TIMEOUT);
0241 }
0242
0243 static int mxsfb_reset_block(struct mxsfb_drm_private *mxsfb)
0244 {
0245 int ret;
0246
0247
0248
0249
0250
0251
0252
0253 ret = clear_poll_bit(mxsfb->base + LCDC_CTRL, CTRL_SFTRST);
0254 if (ret)
0255 return ret;
0256
0257 writel(CTRL_CLKGATE, mxsfb->base + LCDC_CTRL + REG_CLR);
0258
0259 ret = clear_poll_bit(mxsfb->base + LCDC_CTRL, CTRL_SFTRST);
0260 if (ret)
0261 return ret;
0262
0263 ret = clear_poll_bit(mxsfb->base + LCDC_CTRL, CTRL_CLKGATE);
0264 if (ret)
0265 return ret;
0266
0267
0268 writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET);
0269 readl(mxsfb->base + LCDC_CTRL1);
0270 writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_CLR);
0271 readl(mxsfb->base + LCDC_CTRL1);
0272
0273 if (mxsfb->devdata->has_overlay)
0274 writel(0, mxsfb->base + LCDC_AS_CTRL);
0275
0276 return 0;
0277 }
0278
0279 static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb,
0280 struct drm_bridge_state *bridge_state,
0281 const u32 bus_format)
0282 {
0283 struct drm_device *drm = mxsfb->crtc.dev;
0284 struct drm_display_mode *m = &mxsfb->crtc.state->adjusted_mode;
0285 u32 bus_flags = mxsfb->connector->display_info.bus_flags;
0286 int err;
0287
0288 if (mxsfb->bridge && mxsfb->bridge->timings)
0289 bus_flags = mxsfb->bridge->timings->input_bus_flags;
0290 else if (bridge_state)
0291 bus_flags = bridge_state->input_bus_cfg.flags;
0292
0293 DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n",
0294 m->crtc_clock,
0295 (int)(clk_get_rate(mxsfb->clk) / 1000));
0296 DRM_DEV_DEBUG_DRIVER(drm->dev, "Connector bus_flags: 0x%08X\n",
0297 bus_flags);
0298 DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags);
0299
0300
0301 err = mxsfb_reset_block(mxsfb);
0302 if (err)
0303 return;
0304
0305 mxsfb_set_formats(mxsfb, bus_format);
0306
0307 clk_set_rate(mxsfb->clk, m->crtc_clock * 1000);
0308
0309 mxsfb_set_mode(mxsfb, bus_flags);
0310 }
0311
0312 static int mxsfb_crtc_atomic_check(struct drm_crtc *crtc,
0313 struct drm_atomic_state *state)
0314 {
0315 struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
0316 crtc);
0317 bool has_primary = crtc_state->plane_mask &
0318 drm_plane_mask(crtc->primary);
0319
0320
0321 if (crtc_state->active && !has_primary)
0322 return -EINVAL;
0323
0324
0325 return drm_atomic_add_affected_planes(state, crtc);
0326 }
0327
0328 static void mxsfb_crtc_atomic_flush(struct drm_crtc *crtc,
0329 struct drm_atomic_state *state)
0330 {
0331 struct drm_pending_vblank_event *event;
0332
0333 event = crtc->state->event;
0334 crtc->state->event = NULL;
0335
0336 if (!event)
0337 return;
0338
0339 spin_lock_irq(&crtc->dev->event_lock);
0340 if (drm_crtc_vblank_get(crtc) == 0)
0341 drm_crtc_arm_vblank_event(crtc, event);
0342 else
0343 drm_crtc_send_vblank_event(crtc, event);
0344 spin_unlock_irq(&crtc->dev->event_lock);
0345 }
0346
0347 static void mxsfb_crtc_atomic_enable(struct drm_crtc *crtc,
0348 struct drm_atomic_state *state)
0349 {
0350 struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);
0351 struct drm_plane_state *new_pstate = drm_atomic_get_new_plane_state(state,
0352 crtc->primary);
0353 struct drm_bridge_state *bridge_state = NULL;
0354 struct drm_device *drm = mxsfb->drm;
0355 u32 bus_format = 0;
0356 dma_addr_t paddr;
0357
0358 pm_runtime_get_sync(drm->dev);
0359 mxsfb_enable_axi_clk(mxsfb);
0360
0361 drm_crtc_vblank_on(crtc);
0362
0363
0364 if (mxsfb->bridge) {
0365 bridge_state =
0366 drm_atomic_get_new_bridge_state(state,
0367 mxsfb->bridge);
0368 if (!bridge_state)
0369 bus_format = MEDIA_BUS_FMT_FIXED;
0370 else
0371 bus_format = bridge_state->input_bus_cfg.format;
0372
0373 if (bus_format == MEDIA_BUS_FMT_FIXED) {
0374 dev_warn_once(drm->dev,
0375 "Bridge does not provide bus format, assuming MEDIA_BUS_FMT_RGB888_1X24.\n"
0376 "Please fix bridge driver by handling atomic_get_input_bus_fmts.\n");
0377 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
0378 }
0379 }
0380
0381
0382 if (!bus_format && mxsfb->connector->display_info.num_bus_formats)
0383 bus_format = mxsfb->connector->display_info.bus_formats[0];
0384
0385
0386 if (!bus_format)
0387 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
0388
0389 mxsfb_crtc_mode_set_nofb(mxsfb, bridge_state, bus_format);
0390
0391
0392 paddr = drm_fb_cma_get_gem_addr(new_pstate->fb, new_pstate, 0);
0393 if (paddr) {
0394 writel(paddr, mxsfb->base + mxsfb->devdata->cur_buf);
0395 writel(paddr, mxsfb->base + mxsfb->devdata->next_buf);
0396 }
0397
0398 mxsfb_enable_controller(mxsfb);
0399 }
0400
0401 static void mxsfb_crtc_atomic_disable(struct drm_crtc *crtc,
0402 struct drm_atomic_state *state)
0403 {
0404 struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);
0405 struct drm_device *drm = mxsfb->drm;
0406 struct drm_pending_vblank_event *event;
0407
0408 mxsfb_disable_controller(mxsfb);
0409
0410 spin_lock_irq(&drm->event_lock);
0411 event = crtc->state->event;
0412 if (event) {
0413 crtc->state->event = NULL;
0414 drm_crtc_send_vblank_event(crtc, event);
0415 }
0416 spin_unlock_irq(&drm->event_lock);
0417
0418 drm_crtc_vblank_off(crtc);
0419
0420 mxsfb_disable_axi_clk(mxsfb);
0421 pm_runtime_put_sync(drm->dev);
0422 }
0423
0424 static int mxsfb_crtc_enable_vblank(struct drm_crtc *crtc)
0425 {
0426 struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);
0427
0428
0429 writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
0430 writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_SET);
0431
0432 return 0;
0433 }
0434
0435 static void mxsfb_crtc_disable_vblank(struct drm_crtc *crtc)
0436 {
0437 struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);
0438
0439
0440 writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_CLR);
0441 writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
0442 }
0443
0444 static int mxsfb_crtc_set_crc_source(struct drm_crtc *crtc, const char *source)
0445 {
0446 struct mxsfb_drm_private *mxsfb;
0447
0448 if (!crtc)
0449 return -ENODEV;
0450
0451 mxsfb = to_mxsfb_drm_private(crtc->dev);
0452
0453 if (source && strcmp(source, "auto") == 0)
0454 mxsfb->crc_active = true;
0455 else if (!source)
0456 mxsfb->crc_active = false;
0457 else
0458 return -EINVAL;
0459
0460 return 0;
0461 }
0462
0463 static int mxsfb_crtc_verify_crc_source(struct drm_crtc *crtc,
0464 const char *source, size_t *values_cnt)
0465 {
0466 if (!crtc)
0467 return -ENODEV;
0468
0469 if (source && strcmp(source, "auto") != 0) {
0470 DRM_DEBUG_DRIVER("Unknown CRC source %s for %s\n",
0471 source, crtc->name);
0472 return -EINVAL;
0473 }
0474
0475 *values_cnt = 1;
0476 return 0;
0477 }
0478
0479 static const struct drm_crtc_helper_funcs mxsfb_crtc_helper_funcs = {
0480 .atomic_check = mxsfb_crtc_atomic_check,
0481 .atomic_flush = mxsfb_crtc_atomic_flush,
0482 .atomic_enable = mxsfb_crtc_atomic_enable,
0483 .atomic_disable = mxsfb_crtc_atomic_disable,
0484 };
0485
0486 static const struct drm_crtc_funcs mxsfb_crtc_funcs = {
0487 .reset = drm_atomic_helper_crtc_reset,
0488 .destroy = drm_crtc_cleanup,
0489 .set_config = drm_atomic_helper_set_config,
0490 .page_flip = drm_atomic_helper_page_flip,
0491 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
0492 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
0493 .enable_vblank = mxsfb_crtc_enable_vblank,
0494 .disable_vblank = mxsfb_crtc_disable_vblank,
0495 };
0496
0497 static const struct drm_crtc_funcs mxsfb_crtc_with_crc_funcs = {
0498 .reset = drm_atomic_helper_crtc_reset,
0499 .destroy = drm_crtc_cleanup,
0500 .set_config = drm_atomic_helper_set_config,
0501 .page_flip = drm_atomic_helper_page_flip,
0502 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
0503 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
0504 .enable_vblank = mxsfb_crtc_enable_vblank,
0505 .disable_vblank = mxsfb_crtc_disable_vblank,
0506 .set_crc_source = mxsfb_crtc_set_crc_source,
0507 .verify_crc_source = mxsfb_crtc_verify_crc_source,
0508 };
0509
0510
0511
0512
0513
0514 static const struct drm_encoder_funcs mxsfb_encoder_funcs = {
0515 .destroy = drm_encoder_cleanup,
0516 };
0517
0518
0519
0520
0521
0522 static int mxsfb_plane_atomic_check(struct drm_plane *plane,
0523 struct drm_atomic_state *state)
0524 {
0525 struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state,
0526 plane);
0527 struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(plane->dev);
0528 struct drm_crtc_state *crtc_state;
0529
0530 crtc_state = drm_atomic_get_new_crtc_state(state,
0531 &mxsfb->crtc);
0532
0533 return drm_atomic_helper_check_plane_state(plane_state, crtc_state,
0534 DRM_PLANE_HELPER_NO_SCALING,
0535 DRM_PLANE_HELPER_NO_SCALING,
0536 false, true);
0537 }
0538
0539 static void mxsfb_plane_primary_atomic_update(struct drm_plane *plane,
0540 struct drm_atomic_state *state)
0541 {
0542 struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(plane->dev);
0543 struct drm_plane_state *new_pstate = drm_atomic_get_new_plane_state(state,
0544 plane);
0545 dma_addr_t paddr;
0546
0547 paddr = drm_fb_cma_get_gem_addr(new_pstate->fb, new_pstate, 0);
0548 if (paddr)
0549 writel(paddr, mxsfb->base + mxsfb->devdata->next_buf);
0550 }
0551
0552 static void mxsfb_plane_overlay_atomic_update(struct drm_plane *plane,
0553 struct drm_atomic_state *state)
0554 {
0555 struct drm_plane_state *old_pstate = drm_atomic_get_old_plane_state(state,
0556 plane);
0557 struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(plane->dev);
0558 struct drm_plane_state *new_pstate = drm_atomic_get_new_plane_state(state,
0559 plane);
0560 dma_addr_t paddr;
0561 u32 ctrl;
0562
0563 paddr = drm_fb_cma_get_gem_addr(new_pstate->fb, new_pstate, 0);
0564 if (!paddr) {
0565 writel(0, mxsfb->base + LCDC_AS_CTRL);
0566 return;
0567 }
0568
0569
0570
0571
0572
0573
0574
0575 paddr += 64;
0576
0577 writel(paddr, mxsfb->base + LCDC_AS_NEXT_BUF);
0578
0579
0580
0581
0582
0583 if (!old_pstate->fb)
0584 writel(paddr, mxsfb->base + LCDC_AS_BUF);
0585
0586 ctrl = AS_CTRL_AS_ENABLE | AS_CTRL_ALPHA(255);
0587
0588 switch (new_pstate->fb->format->format) {
0589 case DRM_FORMAT_XRGB4444:
0590 ctrl |= AS_CTRL_FORMAT_RGB444 | AS_CTRL_ALPHA_CTRL_OVERRIDE;
0591 break;
0592 case DRM_FORMAT_ARGB4444:
0593 ctrl |= AS_CTRL_FORMAT_ARGB4444 | AS_CTRL_ALPHA_CTRL_EMBEDDED;
0594 break;
0595 case DRM_FORMAT_XRGB1555:
0596 ctrl |= AS_CTRL_FORMAT_RGB555 | AS_CTRL_ALPHA_CTRL_OVERRIDE;
0597 break;
0598 case DRM_FORMAT_ARGB1555:
0599 ctrl |= AS_CTRL_FORMAT_ARGB1555 | AS_CTRL_ALPHA_CTRL_EMBEDDED;
0600 break;
0601 case DRM_FORMAT_RGB565:
0602 ctrl |= AS_CTRL_FORMAT_RGB565 | AS_CTRL_ALPHA_CTRL_OVERRIDE;
0603 break;
0604 case DRM_FORMAT_XRGB8888:
0605 ctrl |= AS_CTRL_FORMAT_RGB888 | AS_CTRL_ALPHA_CTRL_OVERRIDE;
0606 break;
0607 case DRM_FORMAT_ARGB8888:
0608 ctrl |= AS_CTRL_FORMAT_ARGB8888 | AS_CTRL_ALPHA_CTRL_EMBEDDED;
0609 break;
0610 }
0611
0612 writel(ctrl, mxsfb->base + LCDC_AS_CTRL);
0613 }
0614
0615 static bool mxsfb_format_mod_supported(struct drm_plane *plane,
0616 uint32_t format,
0617 uint64_t modifier)
0618 {
0619 return modifier == DRM_FORMAT_MOD_LINEAR;
0620 }
0621
0622 static const struct drm_plane_helper_funcs mxsfb_plane_primary_helper_funcs = {
0623 .atomic_check = mxsfb_plane_atomic_check,
0624 .atomic_update = mxsfb_plane_primary_atomic_update,
0625 };
0626
0627 static const struct drm_plane_helper_funcs mxsfb_plane_overlay_helper_funcs = {
0628 .atomic_check = mxsfb_plane_atomic_check,
0629 .atomic_update = mxsfb_plane_overlay_atomic_update,
0630 };
0631
0632 static const struct drm_plane_funcs mxsfb_plane_funcs = {
0633 .format_mod_supported = mxsfb_format_mod_supported,
0634 .update_plane = drm_atomic_helper_update_plane,
0635 .disable_plane = drm_atomic_helper_disable_plane,
0636 .destroy = drm_plane_cleanup,
0637 .reset = drm_atomic_helper_plane_reset,
0638 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
0639 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
0640 };
0641
0642 static const uint32_t mxsfb_primary_plane_formats[] = {
0643 DRM_FORMAT_RGB565,
0644 DRM_FORMAT_XRGB8888,
0645 };
0646
0647 static const uint32_t mxsfb_overlay_plane_formats[] = {
0648 DRM_FORMAT_XRGB4444,
0649 DRM_FORMAT_ARGB4444,
0650 DRM_FORMAT_XRGB1555,
0651 DRM_FORMAT_ARGB1555,
0652 DRM_FORMAT_RGB565,
0653 DRM_FORMAT_XRGB8888,
0654 DRM_FORMAT_ARGB8888,
0655 };
0656
0657 static const uint64_t mxsfb_modifiers[] = {
0658 DRM_FORMAT_MOD_LINEAR,
0659 DRM_FORMAT_MOD_INVALID
0660 };
0661
0662
0663
0664
0665
0666 int mxsfb_kms_init(struct mxsfb_drm_private *mxsfb)
0667 {
0668 struct drm_encoder *encoder = &mxsfb->encoder;
0669 struct drm_crtc *crtc = &mxsfb->crtc;
0670 int ret;
0671
0672 drm_plane_helper_add(&mxsfb->planes.primary,
0673 &mxsfb_plane_primary_helper_funcs);
0674 ret = drm_universal_plane_init(mxsfb->drm, &mxsfb->planes.primary, 1,
0675 &mxsfb_plane_funcs,
0676 mxsfb_primary_plane_formats,
0677 ARRAY_SIZE(mxsfb_primary_plane_formats),
0678 mxsfb_modifiers, DRM_PLANE_TYPE_PRIMARY,
0679 NULL);
0680 if (ret)
0681 return ret;
0682
0683 if (mxsfb->devdata->has_overlay) {
0684 drm_plane_helper_add(&mxsfb->planes.overlay,
0685 &mxsfb_plane_overlay_helper_funcs);
0686 ret = drm_universal_plane_init(mxsfb->drm,
0687 &mxsfb->planes.overlay, 1,
0688 &mxsfb_plane_funcs,
0689 mxsfb_overlay_plane_formats,
0690 ARRAY_SIZE(mxsfb_overlay_plane_formats),
0691 mxsfb_modifiers, DRM_PLANE_TYPE_OVERLAY,
0692 NULL);
0693 if (ret)
0694 return ret;
0695 }
0696
0697 drm_crtc_helper_add(crtc, &mxsfb_crtc_helper_funcs);
0698 if (mxsfb->devdata->has_crc32) {
0699 ret = drm_crtc_init_with_planes(mxsfb->drm, crtc,
0700 &mxsfb->planes.primary, NULL,
0701 &mxsfb_crtc_with_crc_funcs,
0702 NULL);
0703 } else {
0704 ret = drm_crtc_init_with_planes(mxsfb->drm, crtc,
0705 &mxsfb->planes.primary, NULL,
0706 &mxsfb_crtc_funcs, NULL);
0707 }
0708 if (ret)
0709 return ret;
0710
0711 encoder->possible_crtcs = drm_crtc_mask(crtc);
0712 return drm_encoder_init(mxsfb->drm, encoder, &mxsfb_encoder_funcs,
0713 DRM_MODE_ENCODER_NONE, NULL);
0714 }