0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/clk.h>
0009 #include <linux/io.h>
0010 #include <linux/iopoll.h>
0011 #include <linux/media-bus-format.h>
0012 #include <linux/pm_runtime.h>
0013 #include <linux/spinlock.h>
0014
0015 #include <drm/drm_atomic.h>
0016 #include <drm/drm_atomic_helper.h>
0017 #include <drm/drm_bridge.h>
0018 #include <drm/drm_crtc.h>
0019 #include <drm/drm_encoder.h>
0020 #include <drm/drm_framebuffer.h>
0021 #include <drm/drm_fb_cma_helper.h>
0022 #include <drm/drm_fourcc.h>
0023 #include <drm/drm_gem_atomic_helper.h>
0024 #include <drm/drm_gem_cma_helper.h>
0025 #include <drm/drm_plane.h>
0026 #include <drm/drm_plane_helper.h>
0027 #include <drm/drm_vblank.h>
0028
0029 #include "lcdif_drv.h"
0030 #include "lcdif_regs.h"
0031
0032
0033
0034
0035 static void lcdif_set_formats(struct lcdif_drm_private *lcdif,
0036 const u32 bus_format)
0037 {
0038 struct drm_device *drm = lcdif->drm;
0039 const u32 format = lcdif->crtc.primary->state->fb->format->format;
0040
0041 writel(CSC0_CTRL_BYPASS, lcdif->base + LCDC_V8_CSC0_CTRL);
0042
0043 switch (bus_format) {
0044 case MEDIA_BUS_FMT_RGB565_1X16:
0045 writel(DISP_PARA_LINE_PATTERN_RGB565,
0046 lcdif->base + LCDC_V8_DISP_PARA);
0047 break;
0048 case MEDIA_BUS_FMT_RGB888_1X24:
0049 writel(DISP_PARA_LINE_PATTERN_RGB888,
0050 lcdif->base + LCDC_V8_DISP_PARA);
0051 break;
0052 case MEDIA_BUS_FMT_UYVY8_1X16:
0053 writel(DISP_PARA_LINE_PATTERN_UYVY_H,
0054 lcdif->base + LCDC_V8_DISP_PARA);
0055
0056
0057 writel(CSC0_COEF0_A2(0x096) | CSC0_COEF0_A1(0x04c),
0058 lcdif->base + LCDC_V8_CSC0_COEF0);
0059 writel(CSC0_COEF1_B1(0x7d5) | CSC0_COEF1_A3(0x01d),
0060 lcdif->base + LCDC_V8_CSC0_COEF1);
0061 writel(CSC0_COEF2_B3(0x080) | CSC0_COEF2_B2(0x7ac),
0062 lcdif->base + LCDC_V8_CSC0_COEF2);
0063 writel(CSC0_COEF3_C2(0x795) | CSC0_COEF3_C1(0x080),
0064 lcdif->base + LCDC_V8_CSC0_COEF3);
0065 writel(CSC0_COEF4_D1(0x000) | CSC0_COEF4_C3(0x7ec),
0066 lcdif->base + LCDC_V8_CSC0_COEF4);
0067 writel(CSC0_COEF5_D3(0x080) | CSC0_COEF5_D2(0x080),
0068 lcdif->base + LCDC_V8_CSC0_COEF5);
0069
0070 writel(CSC0_CTRL_CSC_MODE_RGB2YCbCr,
0071 lcdif->base + LCDC_V8_CSC0_CTRL);
0072
0073 break;
0074 default:
0075 dev_err(drm->dev, "Unknown media bus format 0x%x\n", bus_format);
0076 break;
0077 }
0078
0079 switch (format) {
0080 case DRM_FORMAT_RGB565:
0081 writel(CTRLDESCL0_5_BPP_16_RGB565,
0082 lcdif->base + LCDC_V8_CTRLDESCL0_5);
0083 break;
0084 case DRM_FORMAT_RGB888:
0085 writel(CTRLDESCL0_5_BPP_24_RGB888,
0086 lcdif->base + LCDC_V8_CTRLDESCL0_5);
0087 break;
0088 case DRM_FORMAT_XRGB1555:
0089 writel(CTRLDESCL0_5_BPP_16_ARGB1555,
0090 lcdif->base + LCDC_V8_CTRLDESCL0_5);
0091 break;
0092 case DRM_FORMAT_XRGB4444:
0093 writel(CTRLDESCL0_5_BPP_16_ARGB4444,
0094 lcdif->base + LCDC_V8_CTRLDESCL0_5);
0095 break;
0096 case DRM_FORMAT_XBGR8888:
0097 writel(CTRLDESCL0_5_BPP_32_ABGR8888,
0098 lcdif->base + LCDC_V8_CTRLDESCL0_5);
0099 break;
0100 case DRM_FORMAT_XRGB8888:
0101 writel(CTRLDESCL0_5_BPP_32_ARGB8888,
0102 lcdif->base + LCDC_V8_CTRLDESCL0_5);
0103 break;
0104 default:
0105 dev_err(drm->dev, "Unknown pixel format 0x%x\n", format);
0106 break;
0107 }
0108 }
0109
0110 static void lcdif_set_mode(struct lcdif_drm_private *lcdif, u32 bus_flags)
0111 {
0112 struct drm_display_mode *m = &lcdif->crtc.state->adjusted_mode;
0113 u32 ctrl = 0;
0114
0115 if (m->flags & DRM_MODE_FLAG_NHSYNC)
0116 ctrl |= CTRL_INV_HS;
0117 if (m->flags & DRM_MODE_FLAG_NVSYNC)
0118 ctrl |= CTRL_INV_VS;
0119 if (bus_flags & DRM_BUS_FLAG_DE_LOW)
0120 ctrl |= CTRL_INV_DE;
0121 if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
0122 ctrl |= CTRL_INV_PXCK;
0123
0124 writel(ctrl, lcdif->base + LCDC_V8_CTRL);
0125
0126 writel(DISP_SIZE_DELTA_Y(m->crtc_vdisplay) |
0127 DISP_SIZE_DELTA_X(m->crtc_hdisplay),
0128 lcdif->base + LCDC_V8_DISP_SIZE);
0129
0130 writel(HSYN_PARA_BP_H(m->htotal - m->hsync_end) |
0131 HSYN_PARA_FP_H(m->hsync_start - m->hdisplay),
0132 lcdif->base + LCDC_V8_HSYN_PARA);
0133
0134 writel(VSYN_PARA_BP_V(m->vtotal - m->vsync_end) |
0135 VSYN_PARA_FP_V(m->vsync_start - m->vdisplay),
0136 lcdif->base + LCDC_V8_VSYN_PARA);
0137
0138 writel(VSYN_HSYN_WIDTH_PW_V(m->vsync_end - m->vsync_start) |
0139 VSYN_HSYN_WIDTH_PW_H(m->hsync_end - m->hsync_start),
0140 lcdif->base + LCDC_V8_VSYN_HSYN_WIDTH);
0141
0142 writel(CTRLDESCL0_1_HEIGHT(m->crtc_vdisplay) |
0143 CTRLDESCL0_1_WIDTH(m->crtc_hdisplay),
0144 lcdif->base + LCDC_V8_CTRLDESCL0_1);
0145
0146 writel(CTRLDESCL0_3_PITCH(lcdif->crtc.primary->state->fb->pitches[0]),
0147 lcdif->base + LCDC_V8_CTRLDESCL0_3);
0148 }
0149
0150 static void lcdif_enable_controller(struct lcdif_drm_private *lcdif)
0151 {
0152 u32 reg;
0153
0154 reg = readl(lcdif->base + LCDC_V8_DISP_PARA);
0155 reg |= DISP_PARA_DISP_ON;
0156 writel(reg, lcdif->base + LCDC_V8_DISP_PARA);
0157
0158 reg = readl(lcdif->base + LCDC_V8_CTRLDESCL0_5);
0159 reg |= CTRLDESCL0_5_EN;
0160 writel(reg, lcdif->base + LCDC_V8_CTRLDESCL0_5);
0161 }
0162
0163 static void lcdif_disable_controller(struct lcdif_drm_private *lcdif)
0164 {
0165 u32 reg;
0166 int ret;
0167
0168 reg = readl(lcdif->base + LCDC_V8_CTRLDESCL0_5);
0169 reg &= ~CTRLDESCL0_5_EN;
0170 writel(reg, lcdif->base + LCDC_V8_CTRLDESCL0_5);
0171
0172 ret = readl_poll_timeout(lcdif->base + LCDC_V8_CTRLDESCL0_5,
0173 reg, !(reg & CTRLDESCL0_5_EN),
0174 0, 36000);
0175 if (ret)
0176 drm_err(lcdif->drm, "Failed to disable controller!\n");
0177
0178 reg = readl(lcdif->base + LCDC_V8_DISP_PARA);
0179 reg &= ~DISP_PARA_DISP_ON;
0180 writel(reg, lcdif->base + LCDC_V8_DISP_PARA);
0181 }
0182
0183 static void lcdif_reset_block(struct lcdif_drm_private *lcdif)
0184 {
0185 writel(CTRL_SW_RESET, lcdif->base + LCDC_V8_CTRL + REG_SET);
0186 readl(lcdif->base + LCDC_V8_CTRL);
0187 writel(CTRL_SW_RESET, lcdif->base + LCDC_V8_CTRL + REG_CLR);
0188 readl(lcdif->base + LCDC_V8_CTRL);
0189 }
0190
0191 static void lcdif_crtc_mode_set_nofb(struct lcdif_drm_private *lcdif,
0192 struct drm_bridge_state *bridge_state,
0193 const u32 bus_format)
0194 {
0195 struct drm_device *drm = lcdif->crtc.dev;
0196 struct drm_display_mode *m = &lcdif->crtc.state->adjusted_mode;
0197 u32 bus_flags = 0;
0198
0199 if (lcdif->bridge && lcdif->bridge->timings)
0200 bus_flags = lcdif->bridge->timings->input_bus_flags;
0201 else if (bridge_state)
0202 bus_flags = bridge_state->input_bus_cfg.flags;
0203
0204 DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n",
0205 m->crtc_clock,
0206 (int)(clk_get_rate(lcdif->clk) / 1000));
0207 DRM_DEV_DEBUG_DRIVER(drm->dev, "Connector bus_flags: 0x%08X\n",
0208 bus_flags);
0209 DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags);
0210
0211
0212 lcdif_reset_block(lcdif);
0213
0214 lcdif_set_formats(lcdif, bus_format);
0215
0216 lcdif_set_mode(lcdif, bus_flags);
0217 }
0218
0219 static int lcdif_crtc_atomic_check(struct drm_crtc *crtc,
0220 struct drm_atomic_state *state)
0221 {
0222 struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
0223 crtc);
0224 bool has_primary = crtc_state->plane_mask &
0225 drm_plane_mask(crtc->primary);
0226
0227
0228 if (crtc_state->active && !has_primary)
0229 return -EINVAL;
0230
0231 return drm_atomic_add_affected_planes(state, crtc);
0232 }
0233
0234 static void lcdif_crtc_atomic_flush(struct drm_crtc *crtc,
0235 struct drm_atomic_state *state)
0236 {
0237 struct lcdif_drm_private *lcdif = to_lcdif_drm_private(crtc->dev);
0238 struct drm_pending_vblank_event *event;
0239 u32 reg;
0240
0241 reg = readl(lcdif->base + LCDC_V8_CTRLDESCL0_5);
0242 reg |= CTRLDESCL0_5_SHADOW_LOAD_EN;
0243 writel(reg, lcdif->base + LCDC_V8_CTRLDESCL0_5);
0244
0245 event = crtc->state->event;
0246 crtc->state->event = NULL;
0247
0248 if (!event)
0249 return;
0250
0251 spin_lock_irq(&crtc->dev->event_lock);
0252 if (drm_crtc_vblank_get(crtc) == 0)
0253 drm_crtc_arm_vblank_event(crtc, event);
0254 else
0255 drm_crtc_send_vblank_event(crtc, event);
0256 spin_unlock_irq(&crtc->dev->event_lock);
0257 }
0258
0259 static void lcdif_crtc_atomic_enable(struct drm_crtc *crtc,
0260 struct drm_atomic_state *state)
0261 {
0262 struct lcdif_drm_private *lcdif = to_lcdif_drm_private(crtc->dev);
0263 struct drm_plane_state *new_pstate = drm_atomic_get_new_plane_state(state,
0264 crtc->primary);
0265 struct drm_display_mode *m = &lcdif->crtc.state->adjusted_mode;
0266 struct drm_bridge_state *bridge_state = NULL;
0267 struct drm_device *drm = lcdif->drm;
0268 u32 bus_format = 0;
0269 dma_addr_t paddr;
0270
0271
0272 if (lcdif->bridge) {
0273 bridge_state =
0274 drm_atomic_get_new_bridge_state(state,
0275 lcdif->bridge);
0276 if (!bridge_state)
0277 bus_format = MEDIA_BUS_FMT_FIXED;
0278 else
0279 bus_format = bridge_state->input_bus_cfg.format;
0280
0281 if (bus_format == MEDIA_BUS_FMT_FIXED) {
0282 dev_warn_once(drm->dev,
0283 "Bridge does not provide bus format, assuming MEDIA_BUS_FMT_RGB888_1X24.\n"
0284 "Please fix bridge driver by handling atomic_get_input_bus_fmts.\n");
0285 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
0286 }
0287 }
0288
0289
0290 if (!bus_format)
0291 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
0292
0293 clk_set_rate(lcdif->clk, m->crtc_clock * 1000);
0294
0295 pm_runtime_get_sync(drm->dev);
0296
0297 lcdif_crtc_mode_set_nofb(lcdif, bridge_state, bus_format);
0298
0299
0300 paddr = drm_fb_cma_get_gem_addr(new_pstate->fb, new_pstate, 0);
0301 if (paddr) {
0302 writel(lower_32_bits(paddr),
0303 lcdif->base + LCDC_V8_CTRLDESCL_LOW0_4);
0304 writel(CTRLDESCL_HIGH0_4_ADDR_HIGH(upper_32_bits(paddr)),
0305 lcdif->base + LCDC_V8_CTRLDESCL_HIGH0_4);
0306 }
0307 lcdif_enable_controller(lcdif);
0308
0309 drm_crtc_vblank_on(crtc);
0310 }
0311
0312 static void lcdif_crtc_atomic_disable(struct drm_crtc *crtc,
0313 struct drm_atomic_state *state)
0314 {
0315 struct lcdif_drm_private *lcdif = to_lcdif_drm_private(crtc->dev);
0316 struct drm_device *drm = lcdif->drm;
0317 struct drm_pending_vblank_event *event;
0318
0319 drm_crtc_vblank_off(crtc);
0320
0321 lcdif_disable_controller(lcdif);
0322
0323 spin_lock_irq(&drm->event_lock);
0324 event = crtc->state->event;
0325 if (event) {
0326 crtc->state->event = NULL;
0327 drm_crtc_send_vblank_event(crtc, event);
0328 }
0329 spin_unlock_irq(&drm->event_lock);
0330
0331 pm_runtime_put_sync(drm->dev);
0332 }
0333
0334 static int lcdif_crtc_enable_vblank(struct drm_crtc *crtc)
0335 {
0336 struct lcdif_drm_private *lcdif = to_lcdif_drm_private(crtc->dev);
0337
0338
0339 writel(INT_STATUS_D0_VS_BLANK, lcdif->base + LCDC_V8_INT_STATUS_D0);
0340 writel(INT_ENABLE_D0_VS_BLANK_EN, lcdif->base + LCDC_V8_INT_ENABLE_D0);
0341
0342 return 0;
0343 }
0344
0345 static void lcdif_crtc_disable_vblank(struct drm_crtc *crtc)
0346 {
0347 struct lcdif_drm_private *lcdif = to_lcdif_drm_private(crtc->dev);
0348
0349
0350 writel(0, lcdif->base + LCDC_V8_INT_ENABLE_D0);
0351 writel(INT_STATUS_D0_VS_BLANK, lcdif->base + LCDC_V8_INT_STATUS_D0);
0352 }
0353
0354 static const struct drm_crtc_helper_funcs lcdif_crtc_helper_funcs = {
0355 .atomic_check = lcdif_crtc_atomic_check,
0356 .atomic_flush = lcdif_crtc_atomic_flush,
0357 .atomic_enable = lcdif_crtc_atomic_enable,
0358 .atomic_disable = lcdif_crtc_atomic_disable,
0359 };
0360
0361 static const struct drm_crtc_funcs lcdif_crtc_funcs = {
0362 .reset = drm_atomic_helper_crtc_reset,
0363 .destroy = drm_crtc_cleanup,
0364 .set_config = drm_atomic_helper_set_config,
0365 .page_flip = drm_atomic_helper_page_flip,
0366 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
0367 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
0368 .enable_vblank = lcdif_crtc_enable_vblank,
0369 .disable_vblank = lcdif_crtc_disable_vblank,
0370 };
0371
0372
0373
0374
0375
0376 static const struct drm_encoder_funcs lcdif_encoder_funcs = {
0377 .destroy = drm_encoder_cleanup,
0378 };
0379
0380
0381
0382
0383
0384 static int lcdif_plane_atomic_check(struct drm_plane *plane,
0385 struct drm_atomic_state *state)
0386 {
0387 struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state,
0388 plane);
0389 struct lcdif_drm_private *lcdif = to_lcdif_drm_private(plane->dev);
0390 struct drm_crtc_state *crtc_state;
0391
0392 crtc_state = drm_atomic_get_new_crtc_state(state,
0393 &lcdif->crtc);
0394
0395 return drm_atomic_helper_check_plane_state(plane_state, crtc_state,
0396 DRM_PLANE_HELPER_NO_SCALING,
0397 DRM_PLANE_HELPER_NO_SCALING,
0398 false, true);
0399 }
0400
0401 static void lcdif_plane_primary_atomic_update(struct drm_plane *plane,
0402 struct drm_atomic_state *state)
0403 {
0404 struct lcdif_drm_private *lcdif = to_lcdif_drm_private(plane->dev);
0405 struct drm_plane_state *new_pstate = drm_atomic_get_new_plane_state(state,
0406 plane);
0407 dma_addr_t paddr;
0408
0409 paddr = drm_fb_cma_get_gem_addr(new_pstate->fb, new_pstate, 0);
0410 if (paddr) {
0411 writel(lower_32_bits(paddr),
0412 lcdif->base + LCDC_V8_CTRLDESCL_LOW0_4);
0413 writel(CTRLDESCL_HIGH0_4_ADDR_HIGH(upper_32_bits(paddr)),
0414 lcdif->base + LCDC_V8_CTRLDESCL_HIGH0_4);
0415 }
0416 }
0417
0418 static bool lcdif_format_mod_supported(struct drm_plane *plane,
0419 uint32_t format,
0420 uint64_t modifier)
0421 {
0422 return modifier == DRM_FORMAT_MOD_LINEAR;
0423 }
0424
0425 static const struct drm_plane_helper_funcs lcdif_plane_primary_helper_funcs = {
0426 .atomic_check = lcdif_plane_atomic_check,
0427 .atomic_update = lcdif_plane_primary_atomic_update,
0428 };
0429
0430 static const struct drm_plane_funcs lcdif_plane_funcs = {
0431 .format_mod_supported = lcdif_format_mod_supported,
0432 .update_plane = drm_atomic_helper_update_plane,
0433 .disable_plane = drm_atomic_helper_disable_plane,
0434 .destroy = drm_plane_cleanup,
0435 .reset = drm_atomic_helper_plane_reset,
0436 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
0437 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
0438 };
0439
0440 static const u32 lcdif_primary_plane_formats[] = {
0441 DRM_FORMAT_RGB565,
0442 DRM_FORMAT_RGB888,
0443 DRM_FORMAT_XBGR8888,
0444 DRM_FORMAT_XRGB1555,
0445 DRM_FORMAT_XRGB4444,
0446 DRM_FORMAT_XRGB8888,
0447 };
0448
0449 static const u64 lcdif_modifiers[] = {
0450 DRM_FORMAT_MOD_LINEAR,
0451 DRM_FORMAT_MOD_INVALID
0452 };
0453
0454
0455
0456
0457
0458 int lcdif_kms_init(struct lcdif_drm_private *lcdif)
0459 {
0460 struct drm_encoder *encoder = &lcdif->encoder;
0461 struct drm_crtc *crtc = &lcdif->crtc;
0462 int ret;
0463
0464 drm_plane_helper_add(&lcdif->planes.primary,
0465 &lcdif_plane_primary_helper_funcs);
0466 ret = drm_universal_plane_init(lcdif->drm, &lcdif->planes.primary, 1,
0467 &lcdif_plane_funcs,
0468 lcdif_primary_plane_formats,
0469 ARRAY_SIZE(lcdif_primary_plane_formats),
0470 lcdif_modifiers, DRM_PLANE_TYPE_PRIMARY,
0471 NULL);
0472 if (ret)
0473 return ret;
0474
0475 drm_crtc_helper_add(crtc, &lcdif_crtc_helper_funcs);
0476 ret = drm_crtc_init_with_planes(lcdif->drm, crtc,
0477 &lcdif->planes.primary, NULL,
0478 &lcdif_crtc_funcs, NULL);
0479 if (ret)
0480 return ret;
0481
0482 encoder->possible_crtcs = drm_crtc_mask(crtc);
0483 return drm_encoder_init(lcdif->drm, encoder, &lcdif_encoder_funcs,
0484 DRM_MODE_ENCODER_NONE, NULL);
0485 }