0001
0002
0003
0004
0005
0006
0007 #include <linux/clk.h>
0008 #include <linux/component.h>
0009 #include <linux/module.h>
0010 #include <linux/of_device.h>
0011 #include <linux/platform_device.h>
0012
0013 #include <drm/drm_atomic.h>
0014 #include <drm/drm_atomic_helper.h>
0015 #include <drm/drm_plane_helper.h>
0016 #include <drm/drm_probe_helper.h>
0017 #include <drm/drm_vblank.h>
0018
0019 #include "armada_crtc.h"
0020 #include "armada_drm.h"
0021 #include "armada_fb.h"
0022 #include "armada_gem.h"
0023 #include "armada_hw.h"
0024 #include "armada_plane.h"
0025 #include "armada_trace.h"
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081 void
0082 armada_drm_crtc_update_regs(struct armada_crtc *dcrtc, struct armada_regs *regs)
0083 {
0084 while (regs->offset != ~0) {
0085 void __iomem *reg = dcrtc->base + regs->offset;
0086 uint32_t val;
0087
0088 val = regs->mask;
0089 if (val != 0)
0090 val &= readl_relaxed(reg);
0091 writel_relaxed(val | regs->val, reg);
0092 ++regs;
0093 }
0094 }
0095
0096 static void armada_drm_crtc_update(struct armada_crtc *dcrtc, bool enable)
0097 {
0098 uint32_t dumb_ctrl;
0099
0100 dumb_ctrl = dcrtc->cfg_dumb_ctrl;
0101
0102 if (enable)
0103 dumb_ctrl |= CFG_DUMB_ENA;
0104
0105
0106
0107
0108
0109
0110
0111 if (!enable && (dumb_ctrl & DUMB_MASK) == DUMB24_RGB888_0) {
0112 dumb_ctrl &= ~DUMB_MASK;
0113 dumb_ctrl |= DUMB_BLANK;
0114 }
0115
0116 armada_updatel(dumb_ctrl,
0117 ~(CFG_INV_CSYNC | CFG_INV_HSYNC | CFG_INV_VSYNC),
0118 dcrtc->base + LCD_SPU_DUMB_CTRL);
0119 }
0120
0121 static void armada_drm_crtc_queue_state_event(struct drm_crtc *crtc)
0122 {
0123 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
0124 struct drm_pending_vblank_event *event;
0125
0126
0127 event = xchg(&crtc->state->event, NULL);
0128 if (event) {
0129 WARN_ON(drm_crtc_vblank_get(crtc) != 0);
0130 dcrtc->event = event;
0131 }
0132 }
0133
0134 static void armada_drm_update_gamma(struct drm_crtc *crtc)
0135 {
0136 struct drm_property_blob *blob = crtc->state->gamma_lut;
0137 void __iomem *base = drm_to_armada_crtc(crtc)->base;
0138 int i;
0139
0140 if (blob) {
0141 struct drm_color_lut *lut = blob->data;
0142
0143 armada_updatel(CFG_CSB_256x8, CFG_CSB_256x8 | CFG_PDWN256x8,
0144 base + LCD_SPU_SRAM_PARA1);
0145
0146 for (i = 0; i < 256; i++) {
0147 writel_relaxed(drm_color_lut_extract(lut[i].red, 8),
0148 base + LCD_SPU_SRAM_WRDAT);
0149 writel_relaxed(i | SRAM_WRITE | SRAM_GAMMA_YR,
0150 base + LCD_SPU_SRAM_CTRL);
0151 readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN);
0152 writel_relaxed(drm_color_lut_extract(lut[i].green, 8),
0153 base + LCD_SPU_SRAM_WRDAT);
0154 writel_relaxed(i | SRAM_WRITE | SRAM_GAMMA_UG,
0155 base + LCD_SPU_SRAM_CTRL);
0156 readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN);
0157 writel_relaxed(drm_color_lut_extract(lut[i].blue, 8),
0158 base + LCD_SPU_SRAM_WRDAT);
0159 writel_relaxed(i | SRAM_WRITE | SRAM_GAMMA_VB,
0160 base + LCD_SPU_SRAM_CTRL);
0161 readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN);
0162 }
0163 armada_updatel(CFG_GAMMA_ENA, CFG_GAMMA_ENA,
0164 base + LCD_SPU_DMA_CTRL0);
0165 } else {
0166 armada_updatel(0, CFG_GAMMA_ENA, base + LCD_SPU_DMA_CTRL0);
0167 armada_updatel(CFG_PDWN256x8, CFG_CSB_256x8 | CFG_PDWN256x8,
0168 base + LCD_SPU_SRAM_PARA1);
0169 }
0170 }
0171
0172 static enum drm_mode_status armada_drm_crtc_mode_valid(struct drm_crtc *crtc,
0173 const struct drm_display_mode *mode)
0174 {
0175 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
0176
0177 if (mode->vscan > 1)
0178 return MODE_NO_VSCAN;
0179
0180 if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
0181 return MODE_NO_DBLESCAN;
0182
0183 if (mode->flags & DRM_MODE_FLAG_HSKEW)
0184 return MODE_H_ILLEGAL;
0185
0186
0187 if (!dcrtc->variant->has_spu_adv_reg &&
0188 mode->flags & DRM_MODE_FLAG_INTERLACE)
0189 return MODE_NO_INTERLACE;
0190
0191 if (mode->flags & (DRM_MODE_FLAG_BCAST | DRM_MODE_FLAG_PIXMUX |
0192 DRM_MODE_FLAG_CLKDIV2))
0193 return MODE_BAD;
0194
0195 return MODE_OK;
0196 }
0197
0198
0199 static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc,
0200 const struct drm_display_mode *mode, struct drm_display_mode *adj)
0201 {
0202 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
0203 int ret;
0204
0205
0206
0207
0208
0209
0210 drm_mode_set_crtcinfo(adj, CRTC_INTERLACE_HALVE_V);
0211
0212
0213
0214
0215
0216 if (armada_drm_crtc_mode_valid(crtc, adj) != MODE_OK)
0217 return false;
0218
0219
0220 ret = dcrtc->variant->compute_clock(dcrtc, adj, NULL);
0221 if (ret)
0222 return false;
0223
0224 return true;
0225 }
0226
0227
0228 static void armada_drm_crtc_disable_irq(struct armada_crtc *dcrtc, u32 mask)
0229 {
0230 if (dcrtc->irq_ena & mask) {
0231 dcrtc->irq_ena &= ~mask;
0232 writel(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA);
0233 }
0234 }
0235
0236 static void armada_drm_crtc_enable_irq(struct armada_crtc *dcrtc, u32 mask)
0237 {
0238 if ((dcrtc->irq_ena & mask) != mask) {
0239 dcrtc->irq_ena |= mask;
0240 writel(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA);
0241 if (readl_relaxed(dcrtc->base + LCD_SPU_IRQ_ISR) & mask)
0242 writel(0, dcrtc->base + LCD_SPU_IRQ_ISR);
0243 }
0244 }
0245
0246 static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat)
0247 {
0248 struct drm_pending_vblank_event *event;
0249 void __iomem *base = dcrtc->base;
0250
0251 if (stat & DMA_FF_UNDERFLOW)
0252 DRM_ERROR("video underflow on crtc %u\n", dcrtc->num);
0253 if (stat & GRA_FF_UNDERFLOW)
0254 DRM_ERROR("graphics underflow on crtc %u\n", dcrtc->num);
0255
0256 if (stat & VSYNC_IRQ)
0257 drm_crtc_handle_vblank(&dcrtc->crtc);
0258
0259 spin_lock(&dcrtc->irq_lock);
0260 if (stat & GRA_FRAME_IRQ && dcrtc->interlaced) {
0261 int i = stat & GRA_FRAME_IRQ0 ? 0 : 1;
0262 uint32_t val;
0263
0264 writel_relaxed(dcrtc->v[i].spu_v_porch, base + LCD_SPU_V_PORCH);
0265 writel_relaxed(dcrtc->v[i].spu_v_h_total,
0266 base + LCD_SPUT_V_H_TOTAL);
0267
0268 val = readl_relaxed(base + LCD_SPU_ADV_REG);
0269 val &= ~(ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF | ADV_VSYNCOFFEN);
0270 val |= dcrtc->v[i].spu_adv_reg;
0271 writel_relaxed(val, base + LCD_SPU_ADV_REG);
0272 }
0273
0274 if (stat & dcrtc->irq_ena & DUMB_FRAMEDONE) {
0275 if (dcrtc->update_pending) {
0276 armada_drm_crtc_update_regs(dcrtc, dcrtc->regs);
0277 dcrtc->update_pending = false;
0278 }
0279 if (dcrtc->cursor_update) {
0280 writel_relaxed(dcrtc->cursor_hw_pos,
0281 base + LCD_SPU_HWC_OVSA_HPXL_VLN);
0282 writel_relaxed(dcrtc->cursor_hw_sz,
0283 base + LCD_SPU_HWC_HPXL_VLN);
0284 armada_updatel(CFG_HWC_ENA,
0285 CFG_HWC_ENA | CFG_HWC_1BITMOD |
0286 CFG_HWC_1BITENA,
0287 base + LCD_SPU_DMA_CTRL0);
0288 dcrtc->cursor_update = false;
0289 }
0290 armada_drm_crtc_disable_irq(dcrtc, DUMB_FRAMEDONE_ENA);
0291 }
0292 spin_unlock(&dcrtc->irq_lock);
0293
0294 if (stat & VSYNC_IRQ && !dcrtc->update_pending) {
0295 event = xchg(&dcrtc->event, NULL);
0296 if (event) {
0297 spin_lock(&dcrtc->crtc.dev->event_lock);
0298 drm_crtc_send_vblank_event(&dcrtc->crtc, event);
0299 spin_unlock(&dcrtc->crtc.dev->event_lock);
0300 drm_crtc_vblank_put(&dcrtc->crtc);
0301 }
0302 }
0303 }
0304
0305 static irqreturn_t armada_drm_irq(int irq, void *arg)
0306 {
0307 struct armada_crtc *dcrtc = arg;
0308 u32 v, stat = readl_relaxed(dcrtc->base + LCD_SPU_IRQ_ISR);
0309
0310
0311
0312
0313
0314
0315 writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ISR);
0316
0317 trace_armada_drm_irq(&dcrtc->crtc, stat);
0318
0319
0320 v = stat & dcrtc->irq_ena;
0321
0322 if (v & (VSYNC_IRQ|GRA_FRAME_IRQ|DUMB_FRAMEDONE)) {
0323 armada_drm_crtc_irq(dcrtc, stat);
0324 return IRQ_HANDLED;
0325 }
0326 return IRQ_NONE;
0327 }
0328
0329
0330 static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
0331 {
0332 struct drm_display_mode *adj = &crtc->state->adjusted_mode;
0333 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
0334 struct armada_regs regs[17];
0335 uint32_t lm, rm, tm, bm, val, sclk;
0336 unsigned long flags;
0337 unsigned i;
0338 bool interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE);
0339
0340 i = 0;
0341 rm = adj->crtc_hsync_start - adj->crtc_hdisplay;
0342 lm = adj->crtc_htotal - adj->crtc_hsync_end;
0343 bm = adj->crtc_vsync_start - adj->crtc_vdisplay;
0344 tm = adj->crtc_vtotal - adj->crtc_vsync_end;
0345
0346 DRM_DEBUG_KMS("[CRTC:%d:%s] mode " DRM_MODE_FMT "\n",
0347 crtc->base.id, crtc->name, DRM_MODE_ARG(adj));
0348 DRM_DEBUG_KMS("lm %d rm %d tm %d bm %d\n", lm, rm, tm, bm);
0349
0350
0351 dcrtc->variant->compute_clock(dcrtc, adj, &sclk);
0352
0353 armada_reg_queue_set(regs, i, sclk, LCD_CFG_SCLK_DIV);
0354
0355 spin_lock_irqsave(&dcrtc->irq_lock, flags);
0356
0357 dcrtc->interlaced = interlaced;
0358
0359 dcrtc->v[1].spu_v_h_total = adj->crtc_vtotal << 16 |
0360 adj->crtc_htotal;
0361 dcrtc->v[1].spu_v_porch = tm << 16 | bm;
0362 val = adj->crtc_hsync_start;
0363 dcrtc->v[1].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN;
0364
0365 if (interlaced) {
0366
0367 val -= adj->crtc_htotal / 2;
0368 dcrtc->v[0].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN;
0369 dcrtc->v[0].spu_v_h_total = dcrtc->v[1].spu_v_h_total +
0370 (1 << 16);
0371 dcrtc->v[0].spu_v_porch = dcrtc->v[1].spu_v_porch + 1;
0372 } else {
0373 dcrtc->v[0] = dcrtc->v[1];
0374 }
0375
0376 val = adj->crtc_vdisplay << 16 | adj->crtc_hdisplay;
0377
0378 armada_reg_queue_set(regs, i, val, LCD_SPU_V_H_ACTIVE);
0379 armada_reg_queue_set(regs, i, (lm << 16) | rm, LCD_SPU_H_PORCH);
0380 armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_porch, LCD_SPU_V_PORCH);
0381 armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_h_total,
0382 LCD_SPUT_V_H_TOTAL);
0383
0384 if (dcrtc->variant->has_spu_adv_reg)
0385 armada_reg_queue_mod(regs, i, dcrtc->v[0].spu_adv_reg,
0386 ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF |
0387 ADV_VSYNCOFFEN, LCD_SPU_ADV_REG);
0388
0389 val = adj->flags & DRM_MODE_FLAG_NVSYNC ? CFG_VSYNC_INV : 0;
0390 armada_reg_queue_mod(regs, i, val, CFG_VSYNC_INV, LCD_SPU_DMA_CTRL1);
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400 val = 0;
0401 if (adj->flags & DRM_MODE_FLAG_NCSYNC)
0402 val |= CFG_INV_CSYNC;
0403 if (adj->flags & DRM_MODE_FLAG_NHSYNC)
0404 val |= CFG_INV_HSYNC;
0405 if (adj->flags & DRM_MODE_FLAG_NVSYNC)
0406 val |= CFG_INV_VSYNC;
0407 armada_reg_queue_mod(regs, i, val, CFG_INV_CSYNC | CFG_INV_HSYNC |
0408 CFG_INV_VSYNC, LCD_SPU_DUMB_CTRL);
0409 armada_reg_queue_end(regs, i);
0410
0411 armada_drm_crtc_update_regs(dcrtc, regs);
0412 spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
0413 }
0414
0415 static int armada_drm_crtc_atomic_check(struct drm_crtc *crtc,
0416 struct drm_atomic_state *state)
0417 {
0418 struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
0419 crtc);
0420 DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
0421
0422 if (crtc_state->gamma_lut && drm_color_lut_size(crtc_state->gamma_lut) != 256)
0423 return -EINVAL;
0424
0425 if (crtc_state->color_mgmt_changed)
0426 crtc_state->planes_changed = true;
0427
0428 return 0;
0429 }
0430
0431 static void armada_drm_crtc_atomic_begin(struct drm_crtc *crtc,
0432 struct drm_atomic_state *state)
0433 {
0434 struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
0435 crtc);
0436 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
0437
0438 DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
0439
0440 if (crtc_state->color_mgmt_changed)
0441 armada_drm_update_gamma(crtc);
0442
0443 dcrtc->regs_idx = 0;
0444 dcrtc->regs = dcrtc->atomic_regs;
0445 }
0446
0447 static void armada_drm_crtc_atomic_flush(struct drm_crtc *crtc,
0448 struct drm_atomic_state *state)
0449 {
0450 struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
0451 crtc);
0452 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
0453
0454 DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
0455
0456 armada_reg_queue_end(dcrtc->regs, dcrtc->regs_idx);
0457
0458
0459
0460
0461
0462 if (!drm_atomic_crtc_needs_modeset(crtc_state)) {
0463 dcrtc->update_pending = true;
0464 armada_drm_crtc_queue_state_event(crtc);
0465 spin_lock_irq(&dcrtc->irq_lock);
0466 armada_drm_crtc_enable_irq(dcrtc, DUMB_FRAMEDONE_ENA);
0467 spin_unlock_irq(&dcrtc->irq_lock);
0468 } else {
0469 spin_lock_irq(&dcrtc->irq_lock);
0470 armada_drm_crtc_update_regs(dcrtc, dcrtc->regs);
0471 spin_unlock_irq(&dcrtc->irq_lock);
0472 }
0473 }
0474
0475 static void armada_drm_crtc_atomic_disable(struct drm_crtc *crtc,
0476 struct drm_atomic_state *state)
0477 {
0478 struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
0479 crtc);
0480 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
0481 struct drm_pending_vblank_event *event;
0482
0483 DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
0484
0485 if (old_state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
0486 drm_crtc_vblank_put(crtc);
0487
0488 drm_crtc_vblank_off(crtc);
0489 armada_drm_crtc_update(dcrtc, false);
0490
0491 if (!crtc->state->active) {
0492
0493
0494
0495
0496 if (dcrtc->variant->disable)
0497 dcrtc->variant->disable(dcrtc);
0498
0499
0500
0501
0502
0503 event = crtc->state->event;
0504 crtc->state->event = NULL;
0505 if (event) {
0506 spin_lock_irq(&crtc->dev->event_lock);
0507 drm_crtc_send_vblank_event(crtc, event);
0508 spin_unlock_irq(&crtc->dev->event_lock);
0509 }
0510 }
0511 }
0512
0513 static void armada_drm_crtc_atomic_enable(struct drm_crtc *crtc,
0514 struct drm_atomic_state *state)
0515 {
0516 struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
0517 crtc);
0518 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
0519
0520 DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
0521
0522 if (!old_state->active) {
0523
0524
0525
0526
0527
0528 if (dcrtc->variant->enable)
0529 dcrtc->variant->enable(dcrtc, &crtc->state->adjusted_mode);
0530 }
0531 armada_drm_crtc_update(dcrtc, true);
0532 drm_crtc_vblank_on(crtc);
0533
0534 if (crtc->state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
0535 WARN_ON(drm_crtc_vblank_get(crtc));
0536
0537 armada_drm_crtc_queue_state_event(crtc);
0538 }
0539
0540 static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = {
0541 .mode_valid = armada_drm_crtc_mode_valid,
0542 .mode_fixup = armada_drm_crtc_mode_fixup,
0543 .mode_set_nofb = armada_drm_crtc_mode_set_nofb,
0544 .atomic_check = armada_drm_crtc_atomic_check,
0545 .atomic_begin = armada_drm_crtc_atomic_begin,
0546 .atomic_flush = armada_drm_crtc_atomic_flush,
0547 .atomic_disable = armada_drm_crtc_atomic_disable,
0548 .atomic_enable = armada_drm_crtc_atomic_enable,
0549 };
0550
0551 static void armada_load_cursor_argb(void __iomem *base, uint32_t *pix,
0552 unsigned stride, unsigned width, unsigned height)
0553 {
0554 uint32_t addr;
0555 unsigned y;
0556
0557 addr = SRAM_HWC32_RAM1;
0558 for (y = 0; y < height; y++) {
0559 uint32_t *p = &pix[y * stride];
0560 unsigned x;
0561
0562 for (x = 0; x < width; x++, p++) {
0563 uint32_t val = *p;
0564
0565
0566
0567
0568
0569
0570
0571
0572 val = (val & 0xff00ff00) |
0573 (val & 0x000000ff) << 16 |
0574 (val & 0x00ff0000) >> 16;
0575
0576 writel_relaxed(val,
0577 base + LCD_SPU_SRAM_WRDAT);
0578 writel_relaxed(addr | SRAM_WRITE,
0579 base + LCD_SPU_SRAM_CTRL);
0580 readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN);
0581 addr += 1;
0582 if ((addr & 0x00ff) == 0)
0583 addr += 0xf00;
0584 if ((addr & 0x30ff) == 0)
0585 addr = SRAM_HWC32_RAM2;
0586 }
0587 }
0588 }
0589
0590 static void armada_drm_crtc_cursor_tran(void __iomem *base)
0591 {
0592 unsigned addr;
0593
0594 for (addr = 0; addr < 256; addr++) {
0595
0596 writel_relaxed(0x55555555, base + LCD_SPU_SRAM_WRDAT);
0597 writel_relaxed(addr | SRAM_WRITE | SRAM_HWC32_TRAN,
0598 base + LCD_SPU_SRAM_CTRL);
0599 }
0600 }
0601
0602 static int armada_drm_crtc_cursor_update(struct armada_crtc *dcrtc, bool reload)
0603 {
0604 uint32_t xoff, xscr, w = dcrtc->cursor_w, s;
0605 uint32_t yoff, yscr, h = dcrtc->cursor_h;
0606 uint32_t para1;
0607
0608
0609
0610
0611
0612 if (dcrtc->cursor_x < 0) {
0613 xoff = -dcrtc->cursor_x;
0614 xscr = 0;
0615 w -= min(xoff, w);
0616 } else if (dcrtc->cursor_x + w > dcrtc->crtc.mode.hdisplay) {
0617 xoff = 0;
0618 xscr = dcrtc->cursor_x;
0619 w = max_t(int, dcrtc->crtc.mode.hdisplay - dcrtc->cursor_x, 0);
0620 } else {
0621 xoff = 0;
0622 xscr = dcrtc->cursor_x;
0623 }
0624
0625 if (dcrtc->cursor_y < 0) {
0626 yoff = -dcrtc->cursor_y;
0627 yscr = 0;
0628 h -= min(yoff, h);
0629 } else if (dcrtc->cursor_y + h > dcrtc->crtc.mode.vdisplay) {
0630 yoff = 0;
0631 yscr = dcrtc->cursor_y;
0632 h = max_t(int, dcrtc->crtc.mode.vdisplay - dcrtc->cursor_y, 0);
0633 } else {
0634 yoff = 0;
0635 yscr = dcrtc->cursor_y;
0636 }
0637
0638
0639 s = dcrtc->cursor_w;
0640 if (dcrtc->interlaced) {
0641 s *= 2;
0642 yscr /= 2;
0643 h /= 2;
0644 }
0645
0646 if (!dcrtc->cursor_obj || !h || !w) {
0647 spin_lock_irq(&dcrtc->irq_lock);
0648 dcrtc->cursor_update = false;
0649 armada_updatel(0, CFG_HWC_ENA, dcrtc->base + LCD_SPU_DMA_CTRL0);
0650 spin_unlock_irq(&dcrtc->irq_lock);
0651 return 0;
0652 }
0653
0654 spin_lock_irq(&dcrtc->irq_lock);
0655 para1 = readl_relaxed(dcrtc->base + LCD_SPU_SRAM_PARA1);
0656 armada_updatel(CFG_CSB_256x32, CFG_CSB_256x32 | CFG_PDWN256x32,
0657 dcrtc->base + LCD_SPU_SRAM_PARA1);
0658 spin_unlock_irq(&dcrtc->irq_lock);
0659
0660
0661
0662
0663
0664 if (!(para1 & CFG_CSB_256x32)) {
0665 armada_drm_crtc_cursor_tran(dcrtc->base);
0666 reload = true;
0667 }
0668
0669 if (dcrtc->cursor_hw_sz != (h << 16 | w)) {
0670 spin_lock_irq(&dcrtc->irq_lock);
0671 dcrtc->cursor_update = false;
0672 armada_updatel(0, CFG_HWC_ENA, dcrtc->base + LCD_SPU_DMA_CTRL0);
0673 spin_unlock_irq(&dcrtc->irq_lock);
0674 reload = true;
0675 }
0676 if (reload) {
0677 struct armada_gem_object *obj = dcrtc->cursor_obj;
0678 uint32_t *pix;
0679
0680 pix = obj->addr;
0681 pix += yoff * s + xoff;
0682 armada_load_cursor_argb(dcrtc->base, pix, s, w, h);
0683 }
0684
0685
0686 spin_lock_irq(&dcrtc->irq_lock);
0687 dcrtc->cursor_hw_pos = yscr << 16 | xscr;
0688 dcrtc->cursor_hw_sz = h << 16 | w;
0689 dcrtc->cursor_update = true;
0690 armada_drm_crtc_enable_irq(dcrtc, DUMB_FRAMEDONE_ENA);
0691 spin_unlock_irq(&dcrtc->irq_lock);
0692
0693 return 0;
0694 }
0695
0696 static void cursor_update(void *data)
0697 {
0698 armada_drm_crtc_cursor_update(data, true);
0699 }
0700
0701 static int armada_drm_crtc_cursor_set(struct drm_crtc *crtc,
0702 struct drm_file *file, uint32_t handle, uint32_t w, uint32_t h)
0703 {
0704 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
0705 struct armada_gem_object *obj = NULL;
0706 int ret;
0707
0708
0709 if (!dcrtc->variant->has_spu_adv_reg)
0710 return -ENXIO;
0711
0712 if (handle && w > 0 && h > 0) {
0713
0714 if (w > 64 || h > 64 || (w > 32 && h > 32))
0715 return -ENOMEM;
0716
0717 obj = armada_gem_object_lookup(file, handle);
0718 if (!obj)
0719 return -ENOENT;
0720
0721
0722 if (!obj->addr) {
0723 drm_gem_object_put(&obj->obj);
0724 return -EINVAL;
0725 }
0726
0727 if (obj->obj.size < w * h * 4) {
0728 DRM_ERROR("buffer is too small\n");
0729 drm_gem_object_put(&obj->obj);
0730 return -ENOMEM;
0731 }
0732 }
0733
0734 if (dcrtc->cursor_obj) {
0735 dcrtc->cursor_obj->update = NULL;
0736 dcrtc->cursor_obj->update_data = NULL;
0737 drm_gem_object_put(&dcrtc->cursor_obj->obj);
0738 }
0739 dcrtc->cursor_obj = obj;
0740 dcrtc->cursor_w = w;
0741 dcrtc->cursor_h = h;
0742 ret = armada_drm_crtc_cursor_update(dcrtc, true);
0743 if (obj) {
0744 obj->update_data = dcrtc;
0745 obj->update = cursor_update;
0746 }
0747
0748 return ret;
0749 }
0750
0751 static int armada_drm_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
0752 {
0753 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
0754 int ret;
0755
0756
0757 if (!dcrtc->variant->has_spu_adv_reg)
0758 return -EFAULT;
0759
0760 dcrtc->cursor_x = x;
0761 dcrtc->cursor_y = y;
0762 ret = armada_drm_crtc_cursor_update(dcrtc, false);
0763
0764 return ret;
0765 }
0766
0767 static void armada_drm_crtc_destroy(struct drm_crtc *crtc)
0768 {
0769 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
0770 struct armada_private *priv = drm_to_armada_dev(crtc->dev);
0771
0772 if (dcrtc->cursor_obj)
0773 drm_gem_object_put(&dcrtc->cursor_obj->obj);
0774
0775 priv->dcrtc[dcrtc->num] = NULL;
0776 drm_crtc_cleanup(&dcrtc->crtc);
0777
0778 if (dcrtc->variant->disable)
0779 dcrtc->variant->disable(dcrtc);
0780
0781 writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ENA);
0782
0783 of_node_put(dcrtc->crtc.port);
0784
0785 kfree(dcrtc);
0786 }
0787
0788 static int armada_drm_crtc_late_register(struct drm_crtc *crtc)
0789 {
0790 if (IS_ENABLED(CONFIG_DEBUG_FS))
0791 armada_drm_crtc_debugfs_init(drm_to_armada_crtc(crtc));
0792
0793 return 0;
0794 }
0795
0796
0797 static int armada_drm_crtc_enable_vblank(struct drm_crtc *crtc)
0798 {
0799 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
0800 unsigned long flags;
0801
0802 spin_lock_irqsave(&dcrtc->irq_lock, flags);
0803 armada_drm_crtc_enable_irq(dcrtc, VSYNC_IRQ_ENA);
0804 spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
0805 return 0;
0806 }
0807
0808 static void armada_drm_crtc_disable_vblank(struct drm_crtc *crtc)
0809 {
0810 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
0811 unsigned long flags;
0812
0813 spin_lock_irqsave(&dcrtc->irq_lock, flags);
0814 armada_drm_crtc_disable_irq(dcrtc, VSYNC_IRQ_ENA);
0815 spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
0816 }
0817
0818 static const struct drm_crtc_funcs armada_crtc_funcs = {
0819 .reset = drm_atomic_helper_crtc_reset,
0820 .cursor_set = armada_drm_crtc_cursor_set,
0821 .cursor_move = armada_drm_crtc_cursor_move,
0822 .destroy = armada_drm_crtc_destroy,
0823 .set_config = drm_atomic_helper_set_config,
0824 .page_flip = drm_atomic_helper_page_flip,
0825 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
0826 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
0827 .late_register = armada_drm_crtc_late_register,
0828 .enable_vblank = armada_drm_crtc_enable_vblank,
0829 .disable_vblank = armada_drm_crtc_disable_vblank,
0830 };
0831
0832 int armada_crtc_select_clock(struct armada_crtc *dcrtc,
0833 struct armada_clk_result *res,
0834 const struct armada_clocking_params *params,
0835 struct clk *clks[], size_t num_clks,
0836 unsigned long desired_khz)
0837 {
0838 unsigned long desired_hz = desired_khz * 1000;
0839 unsigned long desired_clk_hz;
0840 unsigned long real_clk_hz;
0841 unsigned long real_hz;
0842 unsigned long permillage;
0843 struct clk *clk;
0844 u32 div;
0845 int i;
0846
0847 DRM_DEBUG_KMS("[CRTC:%u:%s] desired clock=%luHz\n",
0848 dcrtc->crtc.base.id, dcrtc->crtc.name, desired_hz);
0849
0850 for (i = 0; i < num_clks; i++) {
0851 clk = clks[i];
0852 if (!clk)
0853 continue;
0854
0855 if (params->settable & BIT(i)) {
0856 real_clk_hz = clk_round_rate(clk, desired_hz);
0857 desired_clk_hz = desired_hz;
0858 } else {
0859 real_clk_hz = clk_get_rate(clk);
0860 desired_clk_hz = real_clk_hz;
0861 }
0862
0863
0864 if (real_clk_hz == desired_hz) {
0865 real_hz = real_clk_hz;
0866 div = 1;
0867 goto found;
0868 }
0869
0870
0871 div = DIV_ROUND_CLOSEST(real_clk_hz, desired_hz);
0872 if (div == 0 || div > params->div_max)
0873 continue;
0874
0875
0876 real_hz = DIV_ROUND_CLOSEST(real_clk_hz, div);
0877
0878 DRM_DEBUG_KMS("[CRTC:%u:%s] clk=%u %luHz div=%u real=%luHz\n",
0879 dcrtc->crtc.base.id, dcrtc->crtc.name,
0880 i, real_clk_hz, div, real_hz);
0881
0882
0883 if (real_hz < desired_hz) {
0884 permillage = real_hz / desired_khz;
0885 if (permillage < params->permillage_min)
0886 continue;
0887 } else {
0888 permillage = DIV_ROUND_UP(real_hz, desired_khz);
0889 if (permillage > params->permillage_max)
0890 continue;
0891 }
0892 goto found;
0893 }
0894
0895 return -ERANGE;
0896
0897 found:
0898 DRM_DEBUG_KMS("[CRTC:%u:%s] selected clk=%u %luHz div=%u real=%luHz\n",
0899 dcrtc->crtc.base.id, dcrtc->crtc.name,
0900 i, real_clk_hz, div, real_hz);
0901
0902 res->desired_clk_hz = desired_clk_hz;
0903 res->clk = clk;
0904 res->div = div;
0905
0906 return i;
0907 }
0908
0909 static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
0910 struct resource *res, int irq, const struct armada_variant *variant,
0911 struct device_node *port)
0912 {
0913 struct armada_private *priv = drm_to_armada_dev(drm);
0914 struct armada_crtc *dcrtc;
0915 struct drm_plane *primary;
0916 void __iomem *base;
0917 int ret;
0918
0919 base = devm_ioremap_resource(dev, res);
0920 if (IS_ERR(base))
0921 return PTR_ERR(base);
0922
0923 dcrtc = kzalloc(sizeof(*dcrtc), GFP_KERNEL);
0924 if (!dcrtc) {
0925 DRM_ERROR("failed to allocate Armada crtc\n");
0926 return -ENOMEM;
0927 }
0928
0929 if (dev != drm->dev)
0930 dev_set_drvdata(dev, dcrtc);
0931
0932 dcrtc->variant = variant;
0933 dcrtc->base = base;
0934 dcrtc->num = drm->mode_config.num_crtc;
0935 dcrtc->cfg_dumb_ctrl = DUMB24_RGB888_0;
0936 dcrtc->spu_iopad_ctrl = CFG_VSCALE_LN_EN | CFG_IOPAD_DUMB24;
0937 spin_lock_init(&dcrtc->irq_lock);
0938 dcrtc->irq_ena = CLEAN_SPU_IRQ_ISR;
0939
0940
0941 writel_relaxed(0x00000001, dcrtc->base + LCD_CFG_SCLK_DIV);
0942 writel_relaxed(0x00000000, dcrtc->base + LCD_SPU_BLANKCOLOR);
0943 writel_relaxed(dcrtc->spu_iopad_ctrl,
0944 dcrtc->base + LCD_SPU_IOPAD_CONTROL);
0945 writel_relaxed(0x00000000, dcrtc->base + LCD_SPU_SRAM_PARA0);
0946 writel_relaxed(CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 |
0947 CFG_PDWN32x32 | CFG_PDWN16x66 | CFG_PDWN32x66 |
0948 CFG_PDWN64x66, dcrtc->base + LCD_SPU_SRAM_PARA1);
0949 writel_relaxed(0x2032ff81, dcrtc->base + LCD_SPU_DMA_CTRL1);
0950 writel_relaxed(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA);
0951 readl_relaxed(dcrtc->base + LCD_SPU_IRQ_ISR);
0952 writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ISR);
0953
0954 ret = devm_request_irq(dev, irq, armada_drm_irq, 0, "armada_drm_crtc",
0955 dcrtc);
0956 if (ret < 0)
0957 goto err_crtc;
0958
0959 if (dcrtc->variant->init) {
0960 ret = dcrtc->variant->init(dcrtc, dev);
0961 if (ret)
0962 goto err_crtc;
0963 }
0964
0965
0966 armada_updatel(CFG_ARBFAST_ENA, 0, dcrtc->base + LCD_SPU_DMA_CTRL0);
0967
0968 priv->dcrtc[dcrtc->num] = dcrtc;
0969
0970 dcrtc->crtc.port = port;
0971
0972 primary = kzalloc(sizeof(*primary), GFP_KERNEL);
0973 if (!primary) {
0974 ret = -ENOMEM;
0975 goto err_crtc;
0976 }
0977
0978 ret = armada_drm_primary_plane_init(drm, primary);
0979 if (ret) {
0980 kfree(primary);
0981 goto err_crtc;
0982 }
0983
0984 ret = drm_crtc_init_with_planes(drm, &dcrtc->crtc, primary, NULL,
0985 &armada_crtc_funcs, NULL);
0986 if (ret)
0987 goto err_crtc_init;
0988
0989 drm_crtc_helper_add(&dcrtc->crtc, &armada_crtc_helper_funcs);
0990
0991 ret = drm_mode_crtc_set_gamma_size(&dcrtc->crtc, 256);
0992 if (ret)
0993 return ret;
0994
0995 drm_crtc_enable_color_mgmt(&dcrtc->crtc, 0, false, 256);
0996
0997 return armada_overlay_plane_create(drm, 1 << dcrtc->num);
0998
0999 err_crtc_init:
1000 primary->funcs->destroy(primary);
1001 err_crtc:
1002 kfree(dcrtc);
1003
1004 return ret;
1005 }
1006
1007 static int
1008 armada_lcd_bind(struct device *dev, struct device *master, void *data)
1009 {
1010 struct platform_device *pdev = to_platform_device(dev);
1011 struct drm_device *drm = data;
1012 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1013 int irq = platform_get_irq(pdev, 0);
1014 const struct armada_variant *variant;
1015 struct device_node *port = NULL;
1016
1017 if (irq < 0)
1018 return irq;
1019
1020 if (!dev->of_node) {
1021 const struct platform_device_id *id;
1022
1023 id = platform_get_device_id(pdev);
1024 if (!id)
1025 return -ENXIO;
1026
1027 variant = (const struct armada_variant *)id->driver_data;
1028 } else {
1029 const struct of_device_id *match;
1030 struct device_node *np, *parent = dev->of_node;
1031
1032 match = of_match_device(dev->driver->of_match_table, dev);
1033 if (!match)
1034 return -ENXIO;
1035
1036 np = of_get_child_by_name(parent, "ports");
1037 if (np)
1038 parent = np;
1039 port = of_get_child_by_name(parent, "port");
1040 of_node_put(np);
1041 if (!port) {
1042 dev_err(dev, "no port node found in %pOF\n", parent);
1043 return -ENXIO;
1044 }
1045
1046 variant = match->data;
1047 }
1048
1049 return armada_drm_crtc_create(drm, dev, res, irq, variant, port);
1050 }
1051
1052 static void
1053 armada_lcd_unbind(struct device *dev, struct device *master, void *data)
1054 {
1055 struct armada_crtc *dcrtc = dev_get_drvdata(dev);
1056
1057 armada_drm_crtc_destroy(&dcrtc->crtc);
1058 }
1059
1060 static const struct component_ops armada_lcd_ops = {
1061 .bind = armada_lcd_bind,
1062 .unbind = armada_lcd_unbind,
1063 };
1064
1065 static int armada_lcd_probe(struct platform_device *pdev)
1066 {
1067 return component_add(&pdev->dev, &armada_lcd_ops);
1068 }
1069
1070 static int armada_lcd_remove(struct platform_device *pdev)
1071 {
1072 component_del(&pdev->dev, &armada_lcd_ops);
1073 return 0;
1074 }
1075
1076 static const struct of_device_id armada_lcd_of_match[] = {
1077 {
1078 .compatible = "marvell,dove-lcd",
1079 .data = &armada510_ops,
1080 },
1081 {}
1082 };
1083 MODULE_DEVICE_TABLE(of, armada_lcd_of_match);
1084
1085 static const struct platform_device_id armada_lcd_platform_ids[] = {
1086 {
1087 .name = "armada-lcd",
1088 .driver_data = (unsigned long)&armada510_ops,
1089 }, {
1090 .name = "armada-510-lcd",
1091 .driver_data = (unsigned long)&armada510_ops,
1092 },
1093 { },
1094 };
1095 MODULE_DEVICE_TABLE(platform, armada_lcd_platform_ids);
1096
1097 struct platform_driver armada_lcd_platform_driver = {
1098 .probe = armada_lcd_probe,
1099 .remove = armada_lcd_remove,
1100 .driver = {
1101 .name = "armada-lcd",
1102 .owner = THIS_MODULE,
1103 .of_match_table = armada_lcd_of_match,
1104 },
1105 .id_table = armada_lcd_platform_ids,
1106 };