Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2022 Marek Vasut <marex@denx.de>
0004  *
0005  * This code is based on drivers/gpu/drm/mxsfb/mxsfb*
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  * CRTC
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         /* CSC: BT.601 Full Range RGB to YCbCr coefficients. */
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); /* Wait ~2 frame times max */
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     /* Mandatory eLCDIF reset as per the Reference Manual */
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     /* The primary plane has to be enabled when the CRTC is active. */
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     /* If there is a bridge attached to the LCDIF, use its bus format */
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     /* If all else fails, default to RGB888_1X24 */
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     /* Write cur_buf as well to avoid an initial corrupt frame */
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     /* Clear and enable VBLANK IRQ */
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     /* Disable and clear VBLANK IRQ */
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  * Encoder
0374  */
0375 
0376 static const struct drm_encoder_funcs lcdif_encoder_funcs = {
0377     .destroy = drm_encoder_cleanup,
0378 };
0379 
0380 /* -----------------------------------------------------------------------------
0381  * Planes
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  * Initialization
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 }