diff options
Diffstat (limited to 'drivers/gpu/drm/stm/ltdc.c')
-rw-r--r-- | drivers/gpu/drm/stm/ltdc.c | 470 |
1 files changed, 156 insertions, 314 deletions
diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c index 1b9483d4f2a4..d394a03632c4 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c @@ -21,7 +21,7 @@ #include <drm/drm_fb_cma_helper.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_of.h> -#include <drm/drm_panel.h> +#include <drm/drm_bridge.h> #include <drm/drm_plane_helper.h> #include <video/videomode.h> @@ -42,52 +42,52 @@ * an extra offset specified with reg_ofs. */ #define REG_OFS_NONE 0 -#define REG_OFS_4 4 /* Insertion of "Layer Configuration 2" reg */ +#define REG_OFS_4 4 /* Insertion of "Layer Conf. 2" reg */ #define REG_OFS (ldev->caps.reg_ofs) -#define LAY_OFS 0x80 /* Register Offset between 2 layers */ +#define LAY_OFS 0x80 /* Register Offset between 2 layers */ /* Global register offsets */ -#define LTDC_IDR 0x0000 /* IDentification */ -#define LTDC_LCR 0x0004 /* Layer Count */ -#define LTDC_SSCR 0x0008 /* Synchronization Size Configuration */ -#define LTDC_BPCR 0x000C /* Back Porch Configuration */ -#define LTDC_AWCR 0x0010 /* Active Width Configuration */ -#define LTDC_TWCR 0x0014 /* Total Width Configuration */ -#define LTDC_GCR 0x0018 /* Global Control */ -#define LTDC_GC1R 0x001C /* Global Configuration 1 */ -#define LTDC_GC2R 0x0020 /* Global Configuration 2 */ -#define LTDC_SRCR 0x0024 /* Shadow Reload Configuration */ -#define LTDC_GACR 0x0028 /* GAmma Correction */ -#define LTDC_BCCR 0x002C /* Background Color Configuration */ -#define LTDC_IER 0x0034 /* Interrupt Enable */ -#define LTDC_ISR 0x0038 /* Interrupt Status */ -#define LTDC_ICR 0x003C /* Interrupt Clear */ -#define LTDC_LIPCR 0x0040 /* Line Interrupt Position Configuration */ -#define LTDC_CPSR 0x0044 /* Current Position Status */ -#define LTDC_CDSR 0x0048 /* Current Display Status */ +#define LTDC_IDR 0x0000 /* IDentification */ +#define LTDC_LCR 0x0004 /* Layer Count */ +#define LTDC_SSCR 0x0008 /* Synchronization Size Configuration */ +#define LTDC_BPCR 0x000C /* Back Porch Configuration */ +#define LTDC_AWCR 0x0010 /* Active Width Configuration */ +#define LTDC_TWCR 0x0014 /* Total Width Configuration */ +#define LTDC_GCR 0x0018 /* Global Control */ +#define LTDC_GC1R 0x001C /* Global Configuration 1 */ +#define LTDC_GC2R 0x0020 /* Global Configuration 2 */ +#define LTDC_SRCR 0x0024 /* Shadow Reload Configuration */ +#define LTDC_GACR 0x0028 /* GAmma Correction */ +#define LTDC_BCCR 0x002C /* Background Color Configuration */ +#define LTDC_IER 0x0034 /* Interrupt Enable */ +#define LTDC_ISR 0x0038 /* Interrupt Status */ +#define LTDC_ICR 0x003C /* Interrupt Clear */ +#define LTDC_LIPCR 0x0040 /* Line Interrupt Position Conf. */ +#define LTDC_CPSR 0x0044 /* Current Position Status */ +#define LTDC_CDSR 0x0048 /* Current Display Status */ /* Layer register offsets */ -#define LTDC_L1LC1R (0x0080) /* L1 Layer Configuration 1 */ -#define LTDC_L1LC2R (0x0084) /* L1 Layer Configuration 2 */ -#define LTDC_L1CR (0x0084 + REG_OFS) /* L1 Control */ -#define LTDC_L1WHPCR (0x0088 + REG_OFS) /* L1 Window Hor Position Config */ -#define LTDC_L1WVPCR (0x008C + REG_OFS) /* L1 Window Vert Position Config */ -#define LTDC_L1CKCR (0x0090 + REG_OFS) /* L1 Color Keying Configuration */ -#define LTDC_L1PFCR (0x0094 + REG_OFS) /* L1 Pixel Format Configuration */ -#define LTDC_L1CACR (0x0098 + REG_OFS) /* L1 Constant Alpha Config */ -#define LTDC_L1DCCR (0x009C + REG_OFS) /* L1 Default Color Configuration */ -#define LTDC_L1BFCR (0x00A0 + REG_OFS) /* L1 Blend Factors Configuration */ -#define LTDC_L1FBBCR (0x00A4 + REG_OFS) /* L1 FrameBuffer Bus Control */ -#define LTDC_L1AFBCR (0x00A8 + REG_OFS) /* L1 AuxFB Control */ -#define LTDC_L1CFBAR (0x00AC + REG_OFS) /* L1 Color FrameBuffer Address */ -#define LTDC_L1CFBLR (0x00B0 + REG_OFS) /* L1 Color FrameBuffer Length */ -#define LTDC_L1CFBLNR (0x00B4 + REG_OFS) /* L1 Color FrameBuffer Line Nb */ -#define LTDC_L1AFBAR (0x00B8 + REG_OFS) /* L1 AuxFB Address */ -#define LTDC_L1AFBLR (0x00BC + REG_OFS) /* L1 AuxFB Length */ -#define LTDC_L1AFBLNR (0x00C0 + REG_OFS) /* L1 AuxFB Line Number */ -#define LTDC_L1CLUTWR (0x00C4 + REG_OFS) /* L1 CLUT Write */ -#define LTDC_L1YS1R (0x00E0 + REG_OFS) /* L1 YCbCr Scale 1 */ -#define LTDC_L1YS2R (0x00E4 + REG_OFS) /* L1 YCbCr Scale 2 */ +#define LTDC_L1LC1R (0x80) /* L1 Layer Configuration 1 */ +#define LTDC_L1LC2R (0x84) /* L1 Layer Configuration 2 */ +#define LTDC_L1CR (0x84 + REG_OFS)/* L1 Control */ +#define LTDC_L1WHPCR (0x88 + REG_OFS)/* L1 Window Hor Position Config */ +#define LTDC_L1WVPCR (0x8C + REG_OFS)/* L1 Window Vert Position Config */ +#define LTDC_L1CKCR (0x90 + REG_OFS)/* L1 Color Keying Configuration */ +#define LTDC_L1PFCR (0x94 + REG_OFS)/* L1 Pixel Format Configuration */ +#define LTDC_L1CACR (0x98 + REG_OFS)/* L1 Constant Alpha Config */ +#define LTDC_L1DCCR (0x9C + REG_OFS)/* L1 Default Color Configuration */ +#define LTDC_L1BFCR (0xA0 + REG_OFS)/* L1 Blend Factors Configuration */ +#define LTDC_L1FBBCR (0xA4 + REG_OFS)/* L1 FrameBuffer Bus Control */ +#define LTDC_L1AFBCR (0xA8 + REG_OFS)/* L1 AuxFB Control */ +#define LTDC_L1CFBAR (0xAC + REG_OFS)/* L1 Color FrameBuffer Address */ +#define LTDC_L1CFBLR (0xB0 + REG_OFS)/* L1 Color FrameBuffer Length */ +#define LTDC_L1CFBLNR (0xB4 + REG_OFS)/* L1 Color FrameBuffer Line Nb */ +#define LTDC_L1AFBAR (0xB8 + REG_OFS)/* L1 AuxFB Address */ +#define LTDC_L1AFBLR (0xBC + REG_OFS)/* L1 AuxFB Length */ +#define LTDC_L1AFBLNR (0xC0 + REG_OFS)/* L1 AuxFB Line Number */ +#define LTDC_L1CLUTWR (0xC4 + REG_OFS)/* L1 CLUT Write */ +#define LTDC_L1YS1R (0xE0 + REG_OFS)/* L1 YCbCr Scale 1 */ +#define LTDC_L1YS2R (0xE4 + REG_OFS)/* L1 YCbCr Scale 2 */ /* Bit definitions */ #define SSCR_VSH GENMASK(10, 0) /* Vertical Synchronization Height */ @@ -104,10 +104,10 @@ #define GCR_LTDCEN BIT(0) /* LTDC ENable */ #define GCR_DEN BIT(16) /* Dither ENable */ -#define GCR_PCPOL BIT(28) /* Pixel Clock POLarity */ -#define GCR_DEPOL BIT(29) /* Data Enable POLarity */ -#define GCR_VSPOL BIT(30) /* Vertical Synchro POLarity */ -#define GCR_HSPOL BIT(31) /* Horizontal Synchro POLarity */ +#define GCR_PCPOL BIT(28) /* Pixel Clock POLarity-Inverted */ +#define GCR_DEPOL BIT(29) /* Data Enable POLarity-High */ +#define GCR_VSPOL BIT(30) /* Vertical Synchro POLarity-High */ +#define GCR_HSPOL BIT(31) /* Horizontal Synchro POLarity-High */ #define GC1R_WBCH GENMASK(3, 0) /* Width of Blue CHannel output */ #define GC1R_WGCH GENMASK(7, 4) /* Width of Green Channel output */ @@ -172,60 +172,52 @@ #define LXCFBLR_CFBLL GENMASK(12, 0) /* Color Frame Buffer Line Length */ #define LXCFBLR_CFBP GENMASK(28, 16) /* Color Frame Buffer Pitch in bytes */ -#define LXCFBLNR_CFBLN GENMASK(10, 0) /* Color Frame Buffer Line Number */ +#define LXCFBLNR_CFBLN GENMASK(10, 0) /* Color Frame Buffer Line Number */ -#define HSPOL_AL 0 /* Horizontal Sync POLarity Active Low */ -#define VSPOL_AL 0 /* Vertical Sync POLarity Active Low */ -#define DEPOL_AL 0 /* Data Enable POLarity Active Low */ -#define PCPOL_IPC 0 /* Input Pixel Clock */ -#define HSPOL_AH GCR_HSPOL /* Horizontal Sync POLarity Active High */ -#define VSPOL_AH GCR_VSPOL /* Vertical Sync POLarity Active High */ -#define DEPOL_AH GCR_DEPOL /* Data Enable POLarity Active High */ -#define PCPOL_IIPC GCR_PCPOL /* Inverted Input Pixel Clock */ -#define CONSTA_MAX 0xFF /* CONSTant Alpha MAX= 1.0 */ -#define BF1_PAXCA 0x600 /* Pixel Alpha x Constant Alpha */ -#define BF1_CA 0x400 /* Constant Alpha */ -#define BF2_1PAXCA 0x007 /* 1 - (Pixel Alpha x Constant Alpha) */ -#define BF2_1CA 0x005 /* 1 - Constant Alpha */ +#define CONSTA_MAX 0xFF /* CONSTant Alpha MAX= 1.0 */ +#define BF1_PAXCA 0x600 /* Pixel Alpha x Constant Alpha */ +#define BF1_CA 0x400 /* Constant Alpha */ +#define BF2_1PAXCA 0x007 /* 1 - (Pixel Alpha x Constant Alpha) */ +#define BF2_1CA 0x005 /* 1 - Constant Alpha */ -#define NB_PF 8 /* Max nb of HW pixel format */ +#define NB_PF 8 /* Max nb of HW pixel format */ enum ltdc_pix_fmt { PF_NONE, /* RGB formats */ - PF_ARGB8888, /* ARGB [32 bits] */ - PF_RGBA8888, /* RGBA [32 bits] */ - PF_RGB888, /* RGB [24 bits] */ - PF_RGB565, /* RGB [16 bits] */ - PF_ARGB1555, /* ARGB A:1 bit RGB:15 bits [16 bits] */ - PF_ARGB4444, /* ARGB A:4 bits R/G/B: 4 bits each [16 bits] */ + PF_ARGB8888, /* ARGB [32 bits] */ + PF_RGBA8888, /* RGBA [32 bits] */ + PF_RGB888, /* RGB [24 bits] */ + PF_RGB565, /* RGB [16 bits] */ + PF_ARGB1555, /* ARGB A:1 bit RGB:15 bits [16 bits] */ + PF_ARGB4444, /* ARGB A:4 bits R/G/B: 4 bits each [16 bits] */ /* Indexed formats */ - PF_L8, /* Indexed 8 bits [8 bits] */ - PF_AL44, /* Alpha:4 bits + indexed 4 bits [8 bits] */ - PF_AL88 /* Alpha:8 bits + indexed 8 bits [16 bits] */ + PF_L8, /* Indexed 8 bits [8 bits] */ + PF_AL44, /* Alpha:4 bits + indexed 4 bits [8 bits] */ + PF_AL88 /* Alpha:8 bits + indexed 8 bits [16 bits] */ }; /* The index gives the encoding of the pixel format for an HW version */ static const enum ltdc_pix_fmt ltdc_pix_fmt_a0[NB_PF] = { - PF_ARGB8888, /* 0x00 */ - PF_RGB888, /* 0x01 */ - PF_RGB565, /* 0x02 */ - PF_ARGB1555, /* 0x03 */ - PF_ARGB4444, /* 0x04 */ - PF_L8, /* 0x05 */ - PF_AL44, /* 0x06 */ - PF_AL88 /* 0x07 */ + PF_ARGB8888, /* 0x00 */ + PF_RGB888, /* 0x01 */ + PF_RGB565, /* 0x02 */ + PF_ARGB1555, /* 0x03 */ + PF_ARGB4444, /* 0x04 */ + PF_L8, /* 0x05 */ + PF_AL44, /* 0x06 */ + PF_AL88 /* 0x07 */ }; static const enum ltdc_pix_fmt ltdc_pix_fmt_a1[NB_PF] = { - PF_ARGB8888, /* 0x00 */ - PF_RGB888, /* 0x01 */ - PF_RGB565, /* 0x02 */ - PF_RGBA8888, /* 0x03 */ - PF_AL44, /* 0x04 */ - PF_L8, /* 0x05 */ - PF_ARGB1555, /* 0x06 */ - PF_ARGB4444 /* 0x07 */ + PF_ARGB8888, /* 0x00 */ + PF_RGB888, /* 0x01 */ + PF_RGB565, /* 0x02 */ + PF_RGBA8888, /* 0x03 */ + PF_AL44, /* 0x04 */ + PF_L8, /* 0x05 */ + PF_ARGB1555, /* 0x06 */ + PF_ARGB4444 /* 0x07 */ }; static inline u32 reg_read(void __iomem *base, u32 reg) @@ -269,11 +261,6 @@ static inline struct ltdc_device *encoder_to_ltdc(struct drm_encoder *enc) return (struct ltdc_device *)enc->dev->dev_private; } -static inline struct ltdc_device *connector_to_ltdc(struct drm_connector *con) -{ - return (struct ltdc_device *)con->dev->dev_private; -} - static inline enum ltdc_pix_fmt to_ltdc_pixelformat(u32 drm_fmt) { enum ltdc_pix_fmt pf; @@ -307,7 +294,7 @@ static inline enum ltdc_pix_fmt to_ltdc_pixelformat(u32 drm_fmt) default: pf = PF_NONE; break; - /* Note: There are no DRM_FORMAT for AL44 and AL88 */ + /* Note: There are no DRM_FORMAT for AL44 and AL88 */ } return pf; @@ -330,8 +317,8 @@ static inline u32 to_drm_pixelformat(enum ltdc_pix_fmt pf) return DRM_FORMAT_ARGB4444; case PF_L8: return DRM_FORMAT_C8; - case PF_AL44: /* No DRM support */ - case PF_AL88: /* No DRM support */ + case PF_AL44: /* No DRM support */ + case PF_AL88: /* No DRM support */ case PF_NONE: default: return 0; @@ -375,18 +362,8 @@ static irqreturn_t ltdc_irq(int irq, void *arg) * DRM_CRTC */ -static void ltdc_crtc_load_lut(struct drm_crtc *crtc) -{ - struct ltdc_device *ldev = crtc_to_ltdc(crtc); - unsigned int i, lay; - - for (lay = 0; lay < ldev->caps.nb_layers; lay++) - for (i = 0; i < 256; i++) - reg_write(ldev->regs, LTDC_L1CLUTWR + lay * LAY_OFS, - ldev->clut[i]); -} - -static void ltdc_crtc_enable(struct drm_crtc *crtc) +static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) { struct ltdc_device *ldev = crtc_to_ltdc(crtc); @@ -407,7 +384,8 @@ static void ltdc_crtc_enable(struct drm_crtc *crtc) drm_crtc_vblank_on(crtc); } -static void ltdc_crtc_disable(struct drm_crtc *crtc) +static void ltdc_crtc_atomic_disable(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) { struct ltdc_device *ldev = crtc_to_ltdc(crtc); @@ -462,20 +440,20 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) clk_enable(ldev->pixel_clk); - /* Configures the HS, VS, DE and PC polarities. */ - val = HSPOL_AL | VSPOL_AL | DEPOL_AL | PCPOL_IPC; + /* Configures the HS, VS, DE and PC polarities. Default Active Low */ + val = 0; if (vm.flags & DISPLAY_FLAGS_HSYNC_HIGH) - val |= HSPOL_AH; + val |= GCR_HSPOL; if (vm.flags & DISPLAY_FLAGS_VSYNC_HIGH) - val |= VSPOL_AH; + val |= GCR_VSPOL; if (vm.flags & DISPLAY_FLAGS_DE_HIGH) - val |= DEPOL_AH; + val |= GCR_DEPOL; if (vm.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) - val |= PCPOL_IIPC; + val |= GCR_PCPOL; reg_update_bits(ldev->regs, LTDC_GCR, GCR_HSPOL | GCR_VSPOL | GCR_DEPOL | GCR_PCPOL, val); @@ -522,12 +500,11 @@ static void ltdc_crtc_atomic_flush(struct drm_crtc *crtc, } } -static struct drm_crtc_helper_funcs ltdc_crtc_helper_funcs = { - .load_lut = ltdc_crtc_load_lut, - .enable = ltdc_crtc_enable, - .disable = ltdc_crtc_disable, +static const struct drm_crtc_helper_funcs ltdc_crtc_helper_funcs = { .mode_set_nofb = ltdc_crtc_mode_set_nofb, .atomic_flush = ltdc_crtc_atomic_flush, + .atomic_enable = ltdc_crtc_atomic_enable, + .atomic_disable = ltdc_crtc_atomic_disable, }; int ltdc_crtc_enable_vblank(struct drm_device *ddev, unsigned int pipe) @@ -548,7 +525,7 @@ void ltdc_crtc_disable_vblank(struct drm_device *ddev, unsigned int pipe) reg_clear(ldev->regs, LTDC_IER, IER_LIE); } -static struct drm_crtc_funcs ltdc_crtc_funcs = { +static const struct drm_crtc_funcs ltdc_crtc_funcs = { .destroy = drm_crtc_cleanup, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, @@ -613,11 +590,11 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, src_w = state->src_w >> 16; src_h = state->src_h >> 16; - DRM_DEBUG_DRIVER( - "plane:%d fb:%d (%dx%d)@(%d,%d) -> (%dx%d)@(%d,%d)\n", - plane->base.id, fb->base.id, - src_w, src_h, src_x, src_y, - state->crtc_w, state->crtc_h, state->crtc_x, state->crtc_y); + DRM_DEBUG_DRIVER("plane:%d fb:%d (%dx%d)@(%d,%d) -> (%dx%d)@(%d,%d)\n", + plane->base.id, fb->base.id, + src_w, src_h, src_x, src_y, + state->crtc_w, state->crtc_h, + state->crtc_x, state->crtc_y); bpcr = reg_read(ldev->regs, LTDC_BPCR); ahbp = (bpcr & BPCR_AHBP) >> 16; @@ -642,7 +619,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, if (val == NB_PF) { DRM_ERROR("Pixel format %.4s not supported\n", (char *)&fb->format->format); - val = 0; /* set by default ARGB 32 bits */ + val = 0; /* set by default ARGB 32 bits */ } reg_update_bits(ldev->regs, LTDC_L1PFCR + lofs, LXPFCR_PF, val); @@ -656,8 +633,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, /* Specifies the constant alpha value */ val = CONSTA_MAX; - reg_update_bits(ldev->regs, LTDC_L1CACR + lofs, - LXCACR_CONSTA, val); + reg_update_bits(ldev->regs, LTDC_L1CACR + lofs, LXCACR_CONSTA, val); /* Specifies the blending factors */ val = BF1_PAXCA | BF2_1PAXCA; @@ -666,8 +642,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, /* Configures the frame buffer line number */ val = y1 - y0 + 1; - reg_update_bits(ldev->regs, LTDC_L1CFBLNR + lofs, - LXCFBLNR_CFBLN, val); + reg_update_bits(ldev->regs, LTDC_L1CFBLNR + lofs, LXCFBLNR_CFBLN, val); /* Sets the FB address */ paddr = (u32)drm_fb_cma_get_gem_addr(fb, state, 0); @@ -706,11 +681,10 @@ static void ltdc_plane_atomic_disable(struct drm_plane *plane, oldstate->crtc->base.id, plane->base.id); } -static struct drm_plane_funcs ltdc_plane_funcs = { +static const struct drm_plane_funcs ltdc_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, .destroy = drm_plane_cleanup, - .set_property = drm_atomic_helper_plane_set_property, .reset = drm_atomic_helper_plane_reset, .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, @@ -748,7 +722,7 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, ret = drm_universal_plane_init(ddev, plane, possible_crtcs, <dc_plane_funcs, formats, nb_fmt, - type, NULL); + NULL, type, NULL); if (ret < 0) return 0; @@ -773,7 +747,7 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) struct ltdc_device *ldev = ddev->dev_private; struct drm_plane *primary, *overlay; unsigned int i; - int res; + int ret; primary = ltdc_plane_create(ddev, DRM_PLANE_TYPE_PRIMARY); if (!primary) { @@ -781,9 +755,9 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) return -EINVAL; } - res = drm_crtc_init_with_planes(ddev, crtc, primary, NULL, + ret = drm_crtc_init_with_planes(ddev, crtc, primary, NULL, <dc_crtc_funcs, NULL); - if (res) { + if (ret) { DRM_ERROR("Can not initialize CRTC\n"); goto cleanup; } @@ -796,7 +770,7 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) for (i = 1; i < ldev->caps.nb_layers; i++) { overlay = ltdc_plane_create(ddev, DRM_PLANE_TYPE_OVERLAY); if (!overlay) { - res = -ENOMEM; + ret = -ENOMEM; DRM_ERROR("Can not create overlay plane %d\n", i); goto cleanup; } @@ -806,137 +780,42 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) cleanup: ltdc_plane_destroy_all(ddev); - return res; + return ret; } /* * DRM_ENCODER */ -static void ltdc_rgb_encoder_enable(struct drm_encoder *encoder) -{ - struct ltdc_device *ldev = encoder_to_ltdc(encoder); - - DRM_DEBUG_DRIVER("\n"); - - drm_panel_prepare(ldev->panel); - drm_panel_enable(ldev->panel); -} - -static void ltdc_rgb_encoder_disable(struct drm_encoder *encoder) -{ - struct ltdc_device *ldev = encoder_to_ltdc(encoder); - - DRM_DEBUG_DRIVER("\n"); - - drm_panel_disable(ldev->panel); - drm_panel_unprepare(ldev->panel); -} - -static const struct drm_encoder_helper_funcs ltdc_rgb_encoder_helper_funcs = { - .enable = ltdc_rgb_encoder_enable, - .disable = ltdc_rgb_encoder_disable, -}; - -static const struct drm_encoder_funcs ltdc_rgb_encoder_funcs = { +static const struct drm_encoder_funcs ltdc_encoder_funcs = { .destroy = drm_encoder_cleanup, }; -static struct drm_encoder *ltdc_rgb_encoder_create(struct drm_device *ddev) +static int ltdc_encoder_init(struct drm_device *ddev) { + struct ltdc_device *ldev = ddev->dev_private; struct drm_encoder *encoder; + int ret; encoder = devm_kzalloc(ddev->dev, sizeof(*encoder), GFP_KERNEL); if (!encoder) - return NULL; + return -ENOMEM; encoder->possible_crtcs = CRTC_MASK; - encoder->possible_clones = 0; /* No cloning support */ + encoder->possible_clones = 0; /* No cloning support */ - drm_encoder_init(ddev, encoder, <dc_rgb_encoder_funcs, + drm_encoder_init(ddev, encoder, <dc_encoder_funcs, DRM_MODE_ENCODER_DPI, NULL); - drm_encoder_helper_add(encoder, <dc_rgb_encoder_helper_funcs); - - DRM_DEBUG_DRIVER("RGB encoder:%d created\n", encoder->base.id); - - return encoder; -} - -/* - * DRM_CONNECTOR - */ - -static int ltdc_rgb_connector_get_modes(struct drm_connector *connector) -{ - struct drm_device *ddev = connector->dev; - struct ltdc_device *ldev = ddev->dev_private; - int ret = 0; - - DRM_DEBUG_DRIVER("\n"); - - if (ldev->panel) - ret = drm_panel_get_modes(ldev->panel); - - return ret < 0 ? 0 : ret; -} - -static struct drm_connector_helper_funcs ltdc_rgb_connector_helper_funcs = { - .get_modes = ltdc_rgb_connector_get_modes, -}; - -static enum drm_connector_status -ltdc_rgb_connector_detect(struct drm_connector *connector, bool force) -{ - struct ltdc_device *ldev = connector_to_ltdc(connector); - - return ldev->panel ? connector_status_connected : - connector_status_disconnected; -} - -static void ltdc_rgb_connector_destroy(struct drm_connector *connector) -{ - DRM_DEBUG_DRIVER("\n"); - - drm_connector_unregister(connector); - drm_connector_cleanup(connector); -} - -static const struct drm_connector_funcs ltdc_rgb_connector_funcs = { - .dpms = drm_atomic_helper_connector_dpms, - .fill_modes = drm_helper_probe_single_connector_modes, - .detect = ltdc_rgb_connector_detect, - .destroy = ltdc_rgb_connector_destroy, - .reset = drm_atomic_helper_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - -struct drm_connector *ltdc_rgb_connector_create(struct drm_device *ddev) -{ - struct drm_connector *connector; - int err; - - connector = devm_kzalloc(ddev->dev, sizeof(*connector), GFP_KERNEL); - if (!connector) { - DRM_ERROR("Failed to allocate connector\n"); - return NULL; - } - - connector->polled = DRM_CONNECTOR_POLL_HPD; - - err = drm_connector_init(ddev, connector, <dc_rgb_connector_funcs, - DRM_MODE_CONNECTOR_DPI); - if (err) { - DRM_ERROR("Failed to initialize connector\n"); - return NULL; + ret = drm_bridge_attach(encoder, ldev->bridge, NULL); + if (ret) { + drm_encoder_cleanup(encoder); + return -EINVAL; } - drm_connector_helper_add(connector, <dc_rgb_connector_helper_funcs); - - DRM_DEBUG_DRIVER("RGB connector:%d created\n", connector->base.id); + DRM_DEBUG_DRIVER("Bridge encoder:%d created\n", encoder->base.id); - return connector; + return 0; } static int ltdc_get_caps(struct drm_device *ddev) @@ -972,61 +851,26 @@ static int ltdc_get_caps(struct drm_device *ddev) return 0; } -static struct drm_panel *ltdc_get_panel(struct drm_device *ddev) -{ - struct device *dev = ddev->dev; - struct device_node *np = dev->of_node; - struct device_node *entity, *port = NULL; - struct drm_panel *panel = NULL; - - DRM_DEBUG_DRIVER("\n"); - - /* - * Parse ltdc node to get remote port and find RGB panel / HDMI slave - * If a dsi or a bridge (hdmi, lvds...) is connected to ltdc, - * a remote port & RGB panel will not be found. - */ - for_each_endpoint_of_node(np, entity) { - if (!of_device_is_available(entity)) - continue; - - port = of_graph_get_remote_port_parent(entity); - if (port) { - panel = of_drm_find_panel(port); - of_node_put(port); - if (panel) { - DRM_DEBUG_DRIVER("remote panel %s\n", - port->full_name); - } else { - DRM_DEBUG_DRIVER("panel missing\n"); - of_node_put(entity); - } - } - } - - return panel; -} - int ltdc_load(struct drm_device *ddev) { struct platform_device *pdev = to_platform_device(ddev->dev); struct ltdc_device *ldev = ddev->dev_private; struct device *dev = ddev->dev; struct device_node *np = dev->of_node; - struct drm_encoder *encoder; - struct drm_connector *connector = NULL; + struct drm_bridge *bridge; + struct drm_panel *panel; struct drm_crtc *crtc; struct reset_control *rstc; - struct resource res; + struct resource *res; int irq, ret, i; DRM_DEBUG_DRIVER("\n"); - ldev->panel = ltdc_get_panel(ddev); - if (!ldev->panel) - return -EPROBE_DEFER; + ret = drm_of_find_panel_or_bridge(np, 0, 0, &panel, &bridge); + if (ret) + return ret; - rstc = of_reset_control_get(np, NULL); + rstc = devm_reset_control_get_exclusive(dev, NULL); mutex_init(&ldev->err_lock); @@ -1041,15 +885,18 @@ int ltdc_load(struct drm_device *ddev) return -ENODEV; } - if (of_address_to_resource(np, 0, &res)) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { DRM_ERROR("Unable to get resource\n"); - return -ENODEV; + ret = -ENODEV; + goto err; } - ldev->regs = devm_ioremap_resource(dev, &res); + ldev->regs = devm_ioremap_resource(dev, res); if (IS_ERR(ldev->regs)) { DRM_ERROR("Unable to get ltdc registers\n"); - return PTR_ERR(ldev->regs); + ret = PTR_ERR(ldev->regs); + goto err; } for (i = 0; i < MAX_IRQ; i++) { @@ -1062,7 +909,7 @@ int ltdc_load(struct drm_device *ddev) dev_name(dev), ddev); if (ret) { DRM_ERROR("Failed to register LTDC interrupt\n"); - return ret; + goto err; } } @@ -1077,33 +924,27 @@ int ltdc_load(struct drm_device *ddev) if (ret) { DRM_ERROR("hardware identifier (0x%08x) not supported!\n", ldev->caps.hw_version); - return ret; + goto err; } DRM_INFO("ltdc hw version 0x%08x - ready\n", ldev->caps.hw_version); - if (ldev->panel) { - encoder = ltdc_rgb_encoder_create(ddev); - if (!encoder) { - DRM_ERROR("Failed to create RGB encoder\n"); - ret = -EINVAL; + if (panel) { + bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(bridge)) { + DRM_ERROR("Failed to create panel-bridge\n"); + ret = PTR_ERR(bridge); goto err; } + ldev->is_panel_bridge = true; + } - connector = ltdc_rgb_connector_create(ddev); - if (!connector) { - DRM_ERROR("Failed to create RGB connector\n"); - ret = -EINVAL; - goto err; - } + ldev->bridge = bridge; - ret = drm_mode_connector_attach_encoder(connector, encoder); - if (ret) { - DRM_ERROR("Failed to attach connector to encoder\n"); - goto err; - } - - drm_panel_attach(ldev->panel, connector); + ret = ltdc_encoder_init(ddev); + if (ret) { + DRM_ERROR("Failed to init encoder\n"); + goto err; } crtc = devm_kzalloc(dev, sizeof(*crtc), GFP_KERNEL); @@ -1129,9 +970,10 @@ int ltdc_load(struct drm_device *ddev) ddev->irq_enabled = 1; return 0; + err: - if (ldev->panel) - drm_panel_detach(ldev->panel); + if (ldev->is_panel_bridge) + drm_panel_bridge_remove(bridge); clk_disable_unprepare(ldev->pixel_clk); @@ -1144,8 +986,8 @@ void ltdc_unload(struct drm_device *ddev) DRM_DEBUG_DRIVER("\n"); - if (ldev->panel) - drm_panel_detach(ldev->panel); + if (ldev->is_panel_bridge) + drm_panel_bridge_remove(ldev->bridge); clk_disable_unprepare(ldev->pixel_clk); } |