diff options
Diffstat (limited to 'drivers/gpu')
| -rw-r--r-- | drivers/gpu/drm/armada/armada_510.c | 23 | ||||
| -rw-r--r-- | drivers/gpu/drm/armada/armada_crtc.c | 65 | ||||
| -rw-r--r-- | drivers/gpu/drm/armada/armada_crtc.h | 7 | ||||
| -rw-r--r-- | drivers/gpu/drm/armada/armada_drm.h | 13 | ||||
| -rw-r--r-- | drivers/gpu/drm/armada/armada_drv.c | 77 |
5 files changed, 79 insertions, 106 deletions
diff --git a/drivers/gpu/drm/armada/armada_510.c b/drivers/gpu/drm/armada/armada_510.c index 59948eff6095..1bcf1a8c1915 100644 --- a/drivers/gpu/drm/armada/armada_510.c +++ b/drivers/gpu/drm/armada/armada_510.c | |||
| @@ -15,20 +15,19 @@ | |||
| 15 | #include "armada_drm.h" | 15 | #include "armada_drm.h" |
| 16 | #include "armada_hw.h" | 16 | #include "armada_hw.h" |
| 17 | 17 | ||
| 18 | static int armada510_init(struct armada_private *priv, struct device *dev) | 18 | static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev) |
| 19 | { | 19 | { |
| 20 | priv->extclk[0] = devm_clk_get(dev, "ext_ref_clk_1"); | 20 | struct clk *clk; |
| 21 | 21 | ||
| 22 | if (IS_ERR(priv->extclk[0]) && PTR_ERR(priv->extclk[0]) == -ENOENT) | 22 | clk = devm_clk_get(dev, "ext_ref_clk_1"); |
| 23 | priv->extclk[0] = ERR_PTR(-EPROBE_DEFER); | 23 | if (IS_ERR(clk)) |
| 24 | return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER : PTR_ERR(clk); | ||
| 24 | 25 | ||
| 25 | return PTR_RET(priv->extclk[0]); | 26 | dcrtc->extclk[0] = clk; |
| 26 | } | ||
| 27 | 27 | ||
| 28 | static int armada510_crtc_init(struct armada_crtc *dcrtc) | ||
| 29 | { | ||
| 30 | /* Lower the watermark so to eliminate jitter at higher bandwidths */ | 28 | /* Lower the watermark so to eliminate jitter at higher bandwidths */ |
| 31 | armada_updatel(0x20, (1 << 11) | 0xff, dcrtc->base + LCD_CFG_RDREG4F); | 29 | armada_updatel(0x20, (1 << 11) | 0xff, dcrtc->base + LCD_CFG_RDREG4F); |
| 30 | |||
| 32 | return 0; | 31 | return 0; |
| 33 | } | 32 | } |
| 34 | 33 | ||
| @@ -45,8 +44,7 @@ static int armada510_crtc_init(struct armada_crtc *dcrtc) | |||
| 45 | static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc, | 44 | static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc, |
| 46 | const struct drm_display_mode *mode, uint32_t *sclk) | 45 | const struct drm_display_mode *mode, uint32_t *sclk) |
| 47 | { | 46 | { |
| 48 | struct armada_private *priv = dcrtc->crtc.dev->dev_private; | 47 | struct clk *clk = dcrtc->extclk[0]; |
| 49 | struct clk *clk = priv->extclk[0]; | ||
| 50 | int ret; | 48 | int ret; |
| 51 | 49 | ||
| 52 | if (dcrtc->num == 1) | 50 | if (dcrtc->num == 1) |
| @@ -81,7 +79,6 @@ static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc, | |||
| 81 | const struct armada_variant armada510_ops = { | 79 | const struct armada_variant armada510_ops = { |
| 82 | .has_spu_adv_reg = true, | 80 | .has_spu_adv_reg = true, |
| 83 | .spu_adv_reg = ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND, | 81 | .spu_adv_reg = ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND, |
| 84 | .init = armada510_init, | 82 | .init = armada510_crtc_init, |
| 85 | .crtc_init = armada510_crtc_init, | 83 | .compute_clock = armada510_crtc_compute_clock, |
| 86 | .crtc_compute_clock = armada510_crtc_compute_clock, | ||
| 87 | }; | 84 | }; |
diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 81c34f949dfc..afa497489000 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c | |||
| @@ -332,24 +332,23 @@ static void armada_drm_crtc_commit(struct drm_crtc *crtc) | |||
| 332 | static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc, | 332 | static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc, |
| 333 | const struct drm_display_mode *mode, struct drm_display_mode *adj) | 333 | const struct drm_display_mode *mode, struct drm_display_mode *adj) |
| 334 | { | 334 | { |
| 335 | struct armada_private *priv = crtc->dev->dev_private; | ||
| 336 | struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); | 335 | struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); |
| 337 | int ret; | 336 | int ret; |
| 338 | 337 | ||
| 339 | /* We can't do interlaced modes if we don't have the SPU_ADV_REG */ | 338 | /* We can't do interlaced modes if we don't have the SPU_ADV_REG */ |
| 340 | if (!priv->variant->has_spu_adv_reg && | 339 | if (!dcrtc->variant->has_spu_adv_reg && |
| 341 | adj->flags & DRM_MODE_FLAG_INTERLACE) | 340 | adj->flags & DRM_MODE_FLAG_INTERLACE) |
| 342 | return false; | 341 | return false; |
| 343 | 342 | ||
| 344 | /* Check whether the display mode is possible */ | 343 | /* Check whether the display mode is possible */ |
| 345 | ret = priv->variant->crtc_compute_clock(dcrtc, adj, NULL); | 344 | ret = dcrtc->variant->compute_clock(dcrtc, adj, NULL); |
| 346 | if (ret) | 345 | if (ret) |
| 347 | return false; | 346 | return false; |
| 348 | 347 | ||
| 349 | return true; | 348 | return true; |
| 350 | } | 349 | } |
| 351 | 350 | ||
| 352 | void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) | 351 | static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) |
| 353 | { | 352 | { |
| 354 | struct armada_vbl_event *e, *n; | 353 | struct armada_vbl_event *e, *n; |
| 355 | void __iomem *base = dcrtc->base; | 354 | void __iomem *base = dcrtc->base; |
| @@ -410,6 +409,27 @@ void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) | |||
| 410 | } | 409 | } |
| 411 | } | 410 | } |
| 412 | 411 | ||
| 412 | static irqreturn_t armada_drm_irq(int irq, void *arg) | ||
| 413 | { | ||
| 414 | struct armada_crtc *dcrtc = arg; | ||
| 415 | u32 v, stat = readl_relaxed(dcrtc->base + LCD_SPU_IRQ_ISR); | ||
| 416 | |||
| 417 | /* | ||
| 418 | * This is rediculous - rather than writing bits to clear, we | ||
| 419 | * have to set the actual status register value. This is racy. | ||
| 420 | */ | ||
| 421 | writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ISR); | ||
| 422 | |||
| 423 | /* Mask out those interrupts we haven't enabled */ | ||
| 424 | v = stat & dcrtc->irq_ena; | ||
| 425 | |||
| 426 | if (v & (VSYNC_IRQ|GRA_FRAME_IRQ|DUMB_FRAMEDONE)) { | ||
| 427 | armada_drm_crtc_irq(dcrtc, stat); | ||
| 428 | return IRQ_HANDLED; | ||
| 429 | } | ||
| 430 | return IRQ_NONE; | ||
| 431 | } | ||
| 432 | |||
| 413 | /* These are locked by dev->vbl_lock */ | 433 | /* These are locked by dev->vbl_lock */ |
| 414 | void armada_drm_crtc_disable_irq(struct armada_crtc *dcrtc, u32 mask) | 434 | void armada_drm_crtc_disable_irq(struct armada_crtc *dcrtc, u32 mask) |
| 415 | { | 435 | { |
| @@ -470,7 +490,6 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, | |||
| 470 | struct drm_display_mode *mode, struct drm_display_mode *adj, | 490 | struct drm_display_mode *mode, struct drm_display_mode *adj, |
| 471 | int x, int y, struct drm_framebuffer *old_fb) | 491 | int x, int y, struct drm_framebuffer *old_fb) |
| 472 | { | 492 | { |
| 473 | struct armada_private *priv = crtc->dev->dev_private; | ||
| 474 | struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); | 493 | struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); |
| 475 | struct armada_regs regs[17]; | 494 | struct armada_regs regs[17]; |
| 476 | uint32_t lm, rm, tm, bm, val, sclk; | 495 | uint32_t lm, rm, tm, bm, val, sclk; |
| @@ -515,7 +534,7 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, | |||
| 515 | } | 534 | } |
| 516 | 535 | ||
| 517 | /* Now compute the divider for real */ | 536 | /* Now compute the divider for real */ |
| 518 | priv->variant->crtc_compute_clock(dcrtc, adj, &sclk); | 537 | dcrtc->variant->compute_clock(dcrtc, adj, &sclk); |
| 519 | 538 | ||
| 520 | /* Ensure graphic fifo is enabled */ | 539 | /* Ensure graphic fifo is enabled */ |
| 521 | armada_reg_queue_mod(regs, i, 0, CFG_PDWN64x66, LCD_SPU_SRAM_PARA1); | 540 | armada_reg_queue_mod(regs, i, 0, CFG_PDWN64x66, LCD_SPU_SRAM_PARA1); |
| @@ -537,7 +556,7 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, | |||
| 537 | dcrtc->v[1].spu_v_porch = tm << 16 | bm; | 556 | dcrtc->v[1].spu_v_porch = tm << 16 | bm; |
| 538 | val = adj->crtc_hsync_start; | 557 | val = adj->crtc_hsync_start; |
| 539 | dcrtc->v[1].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN | | 558 | dcrtc->v[1].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN | |
| 540 | priv->variant->spu_adv_reg; | 559 | dcrtc->variant->spu_adv_reg; |
| 541 | 560 | ||
| 542 | if (interlaced) { | 561 | if (interlaced) { |
| 543 | /* Odd interlaced frame */ | 562 | /* Odd interlaced frame */ |
| @@ -546,7 +565,7 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, | |||
| 546 | dcrtc->v[0].spu_v_porch = dcrtc->v[1].spu_v_porch + 1; | 565 | dcrtc->v[0].spu_v_porch = dcrtc->v[1].spu_v_porch + 1; |
| 547 | val = adj->crtc_hsync_start - adj->crtc_htotal / 2; | 566 | val = adj->crtc_hsync_start - adj->crtc_htotal / 2; |
| 548 | dcrtc->v[0].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN | | 567 | dcrtc->v[0].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN | |
| 549 | priv->variant->spu_adv_reg; | 568 | dcrtc->variant->spu_adv_reg; |
| 550 | } else { | 569 | } else { |
| 551 | dcrtc->v[0] = dcrtc->v[1]; | 570 | dcrtc->v[0] = dcrtc->v[1]; |
| 552 | } | 571 | } |
| @@ -561,7 +580,7 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, | |||
| 561 | armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_h_total, | 580 | armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_h_total, |
| 562 | LCD_SPUT_V_H_TOTAL); | 581 | LCD_SPUT_V_H_TOTAL); |
| 563 | 582 | ||
| 564 | if (priv->variant->has_spu_adv_reg) { | 583 | if (dcrtc->variant->has_spu_adv_reg) { |
| 565 | armada_reg_queue_mod(regs, i, dcrtc->v[0].spu_adv_reg, | 584 | armada_reg_queue_mod(regs, i, dcrtc->v[0].spu_adv_reg, |
| 566 | ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF | | 585 | ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF | |
| 567 | ADV_VSYNCOFFEN, LCD_SPU_ADV_REG); | 586 | ADV_VSYNCOFFEN, LCD_SPU_ADV_REG); |
| @@ -805,12 +824,11 @@ static int armada_drm_crtc_cursor_set(struct drm_crtc *crtc, | |||
| 805 | { | 824 | { |
| 806 | struct drm_device *dev = crtc->dev; | 825 | struct drm_device *dev = crtc->dev; |
| 807 | struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); | 826 | struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); |
| 808 | struct armada_private *priv = crtc->dev->dev_private; | ||
| 809 | struct armada_gem_object *obj = NULL; | 827 | struct armada_gem_object *obj = NULL; |
| 810 | int ret; | 828 | int ret; |
| 811 | 829 | ||
| 812 | /* If no cursor support, replicate drm's return value */ | 830 | /* If no cursor support, replicate drm's return value */ |
| 813 | if (!priv->variant->has_spu_adv_reg) | 831 | if (!dcrtc->variant->has_spu_adv_reg) |
| 814 | return -ENXIO; | 832 | return -ENXIO; |
| 815 | 833 | ||
| 816 | if (handle && w > 0 && h > 0) { | 834 | if (handle && w > 0 && h > 0) { |
| @@ -858,11 +876,10 @@ static int armada_drm_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) | |||
| 858 | { | 876 | { |
| 859 | struct drm_device *dev = crtc->dev; | 877 | struct drm_device *dev = crtc->dev; |
| 860 | struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); | 878 | struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); |
| 861 | struct armada_private *priv = crtc->dev->dev_private; | ||
| 862 | int ret; | 879 | int ret; |
| 863 | 880 | ||
| 864 | /* If no cursor support, replicate drm's return value */ | 881 | /* If no cursor support, replicate drm's return value */ |
| 865 | if (!priv->variant->has_spu_adv_reg) | 882 | if (!dcrtc->variant->has_spu_adv_reg) |
| 866 | return -EFAULT; | 883 | return -EFAULT; |
| 867 | 884 | ||
| 868 | mutex_lock(&dev->struct_mutex); | 885 | mutex_lock(&dev->struct_mutex); |
| @@ -888,6 +905,8 @@ static void armada_drm_crtc_destroy(struct drm_crtc *crtc) | |||
| 888 | if (!IS_ERR(dcrtc->clk)) | 905 | if (!IS_ERR(dcrtc->clk)) |
| 889 | clk_disable_unprepare(dcrtc->clk); | 906 | clk_disable_unprepare(dcrtc->clk); |
| 890 | 907 | ||
| 908 | writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ENA); | ||
| 909 | |||
| 891 | kfree(dcrtc); | 910 | kfree(dcrtc); |
| 892 | } | 911 | } |
| 893 | 912 | ||
| @@ -1027,8 +1046,8 @@ static int armada_drm_crtc_create_properties(struct drm_device *dev) | |||
| 1027 | return 0; | 1046 | return 0; |
| 1028 | } | 1047 | } |
| 1029 | 1048 | ||
| 1030 | int armada_drm_crtc_create(struct drm_device *dev, unsigned num, | 1049 | int armada_drm_crtc_create(struct drm_device *dev, struct resource *res, |
| 1031 | struct resource *res) | 1050 | int irq, const struct armada_variant *variant) |
| 1032 | { | 1051 | { |
| 1033 | struct armada_private *priv = dev->dev_private; | 1052 | struct armada_private *priv = dev->dev_private; |
| 1034 | struct armada_crtc *dcrtc; | 1053 | struct armada_crtc *dcrtc; |
| @@ -1051,8 +1070,9 @@ int armada_drm_crtc_create(struct drm_device *dev, unsigned num, | |||
| 1051 | return -ENOMEM; | 1070 | return -ENOMEM; |
| 1052 | } | 1071 | } |
| 1053 | 1072 | ||
| 1073 | dcrtc->variant = variant; | ||
| 1054 | dcrtc->base = base; | 1074 | dcrtc->base = base; |
| 1055 | dcrtc->num = num; | 1075 | dcrtc->num = dev->mode_config.num_crtc; |
| 1056 | dcrtc->clk = ERR_PTR(-EINVAL); | 1076 | dcrtc->clk = ERR_PTR(-EINVAL); |
| 1057 | dcrtc->csc_yuv_mode = CSC_AUTO; | 1077 | dcrtc->csc_yuv_mode = CSC_AUTO; |
| 1058 | dcrtc->csc_rgb_mode = CSC_AUTO; | 1078 | dcrtc->csc_rgb_mode = CSC_AUTO; |
| @@ -1074,9 +1094,18 @@ int armada_drm_crtc_create(struct drm_device *dev, unsigned num, | |||
| 1074 | CFG_PDWN64x66, dcrtc->base + LCD_SPU_SRAM_PARA1); | 1094 | CFG_PDWN64x66, dcrtc->base + LCD_SPU_SRAM_PARA1); |
| 1075 | writel_relaxed(0x2032ff81, dcrtc->base + LCD_SPU_DMA_CTRL1); | 1095 | writel_relaxed(0x2032ff81, dcrtc->base + LCD_SPU_DMA_CTRL1); |
| 1076 | writel_relaxed(0x00000000, dcrtc->base + LCD_SPU_GRA_OVSA_HPXL_VLN); | 1096 | writel_relaxed(0x00000000, dcrtc->base + LCD_SPU_GRA_OVSA_HPXL_VLN); |
| 1097 | writel_relaxed(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA); | ||
| 1098 | writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ISR); | ||
| 1099 | |||
| 1100 | ret = devm_request_irq(dev, irq, armada_drm_irq, 0, "armada_drm_crtc", | ||
| 1101 | dcrtc); | ||
| 1102 | if (ret < 0) { | ||
| 1103 | kfree(dcrtc); | ||
| 1104 | return ret; | ||
| 1105 | } | ||
| 1077 | 1106 | ||
| 1078 | if (priv->variant->crtc_init) { | 1107 | if (dcrtc->variant->init) { |
| 1079 | ret = priv->variant->crtc_init(dcrtc); | 1108 | ret = dcrtc->variant->init(dcrtc, dev->dev); |
| 1080 | if (ret) { | 1109 | if (ret) { |
| 1081 | kfree(dcrtc); | 1110 | kfree(dcrtc); |
| 1082 | return ret; | 1111 | return ret; |
diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 9c10a07e7492..73efcfcdf814 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h | |||
| @@ -32,12 +32,15 @@ struct armada_regs { | |||
| 32 | armada_reg_queue_mod(_r, _i, 0, 0, ~0) | 32 | armada_reg_queue_mod(_r, _i, 0, 0, ~0) |
| 33 | 33 | ||
| 34 | struct armada_frame_work; | 34 | struct armada_frame_work; |
| 35 | struct armada_variant; | ||
| 35 | 36 | ||
| 36 | struct armada_crtc { | 37 | struct armada_crtc { |
| 37 | struct drm_crtc crtc; | 38 | struct drm_crtc crtc; |
| 39 | const struct armada_variant *variant; | ||
| 38 | unsigned num; | 40 | unsigned num; |
| 39 | void __iomem *base; | 41 | void __iomem *base; |
| 40 | struct clk *clk; | 42 | struct clk *clk; |
| 43 | struct clk *extclk[2]; | ||
| 41 | struct { | 44 | struct { |
| 42 | uint32_t spu_v_h_total; | 45 | uint32_t spu_v_h_total; |
| 43 | uint32_t spu_v_porch; | 46 | uint32_t spu_v_porch; |
| @@ -72,10 +75,10 @@ struct armada_crtc { | |||
| 72 | }; | 75 | }; |
| 73 | #define drm_to_armada_crtc(c) container_of(c, struct armada_crtc, crtc) | 76 | #define drm_to_armada_crtc(c) container_of(c, struct armada_crtc, crtc) |
| 74 | 77 | ||
| 75 | int armada_drm_crtc_create(struct drm_device *, unsigned, struct resource *); | 78 | int armada_drm_crtc_create(struct drm_device *, struct resource *, int, |
| 79 | const struct armada_variant *); | ||
| 76 | void armada_drm_crtc_gamma_set(struct drm_crtc *, u16, u16, u16, int); | 80 | void armada_drm_crtc_gamma_set(struct drm_crtc *, u16, u16, u16, int); |
| 77 | void armada_drm_crtc_gamma_get(struct drm_crtc *, u16 *, u16 *, u16 *, int); | 81 | void armada_drm_crtc_gamma_get(struct drm_crtc *, u16 *, u16 *, u16 *, int); |
| 78 | void armada_drm_crtc_irq(struct armada_crtc *, u32); | ||
| 79 | void armada_drm_crtc_disable_irq(struct armada_crtc *, u32); | 82 | void armada_drm_crtc_disable_irq(struct armada_crtc *, u32); |
| 80 | void armada_drm_crtc_enable_irq(struct armada_crtc *, u32); | 83 | void armada_drm_crtc_enable_irq(struct armada_crtc *, u32); |
| 81 | void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *); | 84 | void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *); |
diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h index a72cae03b99b..ea63c6c7c66f 100644 --- a/drivers/gpu/drm/armada/armada_drm.h +++ b/drivers/gpu/drm/armada/armada_drm.h | |||
| @@ -59,26 +59,23 @@ void armada_drm_vbl_event_remove_unlocked(struct armada_crtc *, | |||
| 59 | struct armada_private; | 59 | struct armada_private; |
| 60 | 60 | ||
| 61 | struct armada_variant { | 61 | struct armada_variant { |
| 62 | bool has_spu_adv_reg; | 62 | bool has_spu_adv_reg; |
| 63 | uint32_t spu_adv_reg; | 63 | uint32_t spu_adv_reg; |
| 64 | int (*init)(struct armada_private *, struct device *); | 64 | int (*init)(struct armada_crtc *, struct device *); |
| 65 | int (*crtc_init)(struct armada_crtc *); | 65 | int (*compute_clock)(struct armada_crtc *, |
| 66 | int (*crtc_compute_clock)(struct armada_crtc *, | 66 | const struct drm_display_mode *, |
| 67 | const struct drm_display_mode *, | 67 | uint32_t *); |
| 68 | uint32_t *); | ||
| 69 | }; | 68 | }; |
| 70 | 69 | ||
| 71 | /* Variant ops */ | 70 | /* Variant ops */ |
| 72 | extern const struct armada_variant armada510_ops; | 71 | extern const struct armada_variant armada510_ops; |
| 73 | 72 | ||
| 74 | struct armada_private { | 73 | struct armada_private { |
| 75 | const struct armada_variant *variant; | ||
| 76 | struct work_struct fb_unref_work; | 74 | struct work_struct fb_unref_work; |
| 77 | DECLARE_KFIFO(fb_unref, struct drm_framebuffer *, 8); | 75 | DECLARE_KFIFO(fb_unref, struct drm_framebuffer *, 8); |
| 78 | struct drm_fb_helper *fbdev; | 76 | struct drm_fb_helper *fbdev; |
| 79 | struct armada_crtc *dcrtc[2]; | 77 | struct armada_crtc *dcrtc[2]; |
| 80 | struct drm_mm linear; | 78 | struct drm_mm linear; |
| 81 | struct clk *extclk[2]; | ||
| 82 | struct drm_property *csc_yuv_prop; | 79 | struct drm_property *csc_yuv_prop; |
| 83 | struct drm_property *csc_rgb_prop; | 80 | struct drm_property *csc_rgb_prop; |
| 84 | struct drm_property *colorkey_prop; | 81 | struct drm_property *colorkey_prop; |
diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index 8ab3cd1a8cdb..3995be3c686b 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c | |||
| @@ -85,6 +85,7 @@ void armada_drm_queue_unref_work(struct drm_device *dev, | |||
| 85 | static int armada_drm_load(struct drm_device *dev, unsigned long flags) | 85 | static int armada_drm_load(struct drm_device *dev, unsigned long flags) |
| 86 | { | 86 | { |
| 87 | const struct platform_device_id *id; | 87 | const struct platform_device_id *id; |
| 88 | const struct armada_variant *variant; | ||
| 88 | struct armada_private *priv; | 89 | struct armada_private *priv; |
| 89 | struct resource *res[ARRAY_SIZE(priv->dcrtc)]; | 90 | struct resource *res[ARRAY_SIZE(priv->dcrtc)]; |
| 90 | struct resource *mem = NULL; | 91 | struct resource *mem = NULL; |
| @@ -128,11 +129,7 @@ static int armada_drm_load(struct drm_device *dev, unsigned long flags) | |||
| 128 | if (!id) | 129 | if (!id) |
| 129 | return -ENXIO; | 130 | return -ENXIO; |
| 130 | 131 | ||
| 131 | priv->variant = (struct armada_variant *)id->driver_data; | 132 | variant = (const struct armada_variant *)id->driver_data; |
| 132 | |||
| 133 | ret = priv->variant->init(priv, dev->dev); | ||
| 134 | if (ret) | ||
| 135 | return ret; | ||
| 136 | 133 | ||
| 137 | INIT_WORK(&priv->fb_unref_work, armada_drm_unref_work); | 134 | INIT_WORK(&priv->fb_unref_work, armada_drm_unref_work); |
| 138 | INIT_KFIFO(priv->fb_unref); | 135 | INIT_KFIFO(priv->fb_unref); |
| @@ -155,10 +152,16 @@ static int armada_drm_load(struct drm_device *dev, unsigned long flags) | |||
| 155 | 152 | ||
| 156 | /* Create all LCD controllers */ | 153 | /* Create all LCD controllers */ |
| 157 | for (n = 0; n < ARRAY_SIZE(priv->dcrtc); n++) { | 154 | for (n = 0; n < ARRAY_SIZE(priv->dcrtc); n++) { |
| 155 | int irq; | ||
| 156 | |||
| 158 | if (!res[n]) | 157 | if (!res[n]) |
| 159 | break; | 158 | break; |
| 160 | 159 | ||
| 161 | ret = armada_drm_crtc_create(dev, n, res[n]); | 160 | irq = platform_get_irq(dev->platformdev, n); |
| 161 | if (irq < 0) | ||
| 162 | goto err_kms; | ||
| 163 | |||
| 164 | ret = armada_drm_crtc_create(dev, res[n], irq, variant); | ||
| 162 | if (ret) | 165 | if (ret) |
| 163 | goto err_kms; | 166 | goto err_kms; |
| 164 | } | 167 | } |
| @@ -169,11 +172,7 @@ static int armada_drm_load(struct drm_device *dev, unsigned long flags) | |||
| 169 | goto err_kms; | 172 | goto err_kms; |
| 170 | #endif | 173 | #endif |
| 171 | 174 | ||
| 172 | ret = drm_vblank_init(dev, n); | 175 | ret = drm_vblank_init(dev, dev->mode_config.num_crtc); |
| 173 | if (ret) | ||
| 174 | goto err_kms; | ||
| 175 | |||
| 176 | ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0)); | ||
| 177 | if (ret) | 176 | if (ret) |
| 178 | goto err_kms; | 177 | goto err_kms; |
| 179 | 178 | ||
| @@ -181,14 +180,12 @@ static int armada_drm_load(struct drm_device *dev, unsigned long flags) | |||
| 181 | 180 | ||
| 182 | ret = armada_fbdev_init(dev); | 181 | ret = armada_fbdev_init(dev); |
| 183 | if (ret) | 182 | if (ret) |
| 184 | goto err_irq; | 183 | goto err_kms; |
| 185 | 184 | ||
| 186 | drm_kms_helper_poll_init(dev); | 185 | drm_kms_helper_poll_init(dev); |
| 187 | 186 | ||
| 188 | return 0; | 187 | return 0; |
| 189 | 188 | ||
| 190 | err_irq: | ||
| 191 | drm_irq_uninstall(dev); | ||
| 192 | err_kms: | 189 | err_kms: |
| 193 | drm_mode_config_cleanup(dev); | 190 | drm_mode_config_cleanup(dev); |
| 194 | drm_mm_takedown(&priv->linear); | 191 | drm_mm_takedown(&priv->linear); |
| @@ -203,7 +200,6 @@ static int armada_drm_unload(struct drm_device *dev) | |||
| 203 | 200 | ||
| 204 | drm_kms_helper_poll_fini(dev); | 201 | drm_kms_helper_poll_fini(dev); |
| 205 | armada_fbdev_fini(dev); | 202 | armada_fbdev_fini(dev); |
| 206 | drm_irq_uninstall(dev); | ||
| 207 | drm_mode_config_cleanup(dev); | 203 | drm_mode_config_cleanup(dev); |
| 208 | drm_mm_takedown(&priv->linear); | 204 | drm_mm_takedown(&priv->linear); |
| 209 | flush_work(&priv->fb_unref_work); | 205 | flush_work(&priv->fb_unref_work); |
| @@ -259,52 +255,6 @@ static void armada_drm_disable_vblank(struct drm_device *dev, int crtc) | |||
| 259 | armada_drm_crtc_disable_irq(priv->dcrtc[crtc], VSYNC_IRQ_ENA); | 255 | armada_drm_crtc_disable_irq(priv->dcrtc[crtc], VSYNC_IRQ_ENA); |
| 260 | } | 256 | } |
| 261 | 257 | ||
| 262 | static irqreturn_t armada_drm_irq_handler(int irq, void *arg) | ||
| 263 | { | ||
| 264 | struct drm_device *dev = arg; | ||
| 265 | struct armada_private *priv = dev->dev_private; | ||
| 266 | struct armada_crtc *dcrtc = priv->dcrtc[0]; | ||
| 267 | uint32_t v, stat = readl_relaxed(dcrtc->base + LCD_SPU_IRQ_ISR); | ||
| 268 | irqreturn_t handled = IRQ_NONE; | ||
| 269 | |||
| 270 | /* | ||
| 271 | * This is rediculous - rather than writing bits to clear, we | ||
| 272 | * have to set the actual status register value. This is racy. | ||
| 273 | */ | ||
| 274 | writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ISR); | ||
| 275 | |||
| 276 | /* Mask out those interrupts we haven't enabled */ | ||
| 277 | v = stat & dcrtc->irq_ena; | ||
| 278 | |||
| 279 | if (v & (VSYNC_IRQ|GRA_FRAME_IRQ|DUMB_FRAMEDONE)) { | ||
| 280 | armada_drm_crtc_irq(dcrtc, stat); | ||
| 281 | handled = IRQ_HANDLED; | ||
| 282 | } | ||
| 283 | |||
| 284 | return handled; | ||
| 285 | } | ||
| 286 | |||
| 287 | static int armada_drm_irq_postinstall(struct drm_device *dev) | ||
| 288 | { | ||
| 289 | struct armada_private *priv = dev->dev_private; | ||
| 290 | struct armada_crtc *dcrtc = priv->dcrtc[0]; | ||
| 291 | |||
| 292 | spin_lock_irq(&dev->vbl_lock); | ||
| 293 | writel_relaxed(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA); | ||
| 294 | writel(0, dcrtc->base + LCD_SPU_IRQ_ISR); | ||
| 295 | spin_unlock_irq(&dev->vbl_lock); | ||
| 296 | |||
| 297 | return 0; | ||
| 298 | } | ||
| 299 | |||
| 300 | static void armada_drm_irq_uninstall(struct drm_device *dev) | ||
| 301 | { | ||
| 302 | struct armada_private *priv = dev->dev_private; | ||
| 303 | struct armada_crtc *dcrtc = priv->dcrtc[0]; | ||
| 304 | |||
| 305 | writel(0, dcrtc->base + LCD_SPU_IRQ_ENA); | ||
| 306 | } | ||
| 307 | |||
| 308 | static struct drm_ioctl_desc armada_ioctls[] = { | 258 | static struct drm_ioctl_desc armada_ioctls[] = { |
| 309 | DRM_IOCTL_DEF_DRV(ARMADA_GEM_CREATE, armada_gem_create_ioctl, | 259 | DRM_IOCTL_DEF_DRV(ARMADA_GEM_CREATE, armada_gem_create_ioctl, |
| 310 | DRM_UNLOCKED), | 260 | DRM_UNLOCKED), |
| @@ -340,9 +290,6 @@ static struct drm_driver armada_drm_driver = { | |||
| 340 | .get_vblank_counter = drm_vblank_count, | 290 | .get_vblank_counter = drm_vblank_count, |
| 341 | .enable_vblank = armada_drm_enable_vblank, | 291 | .enable_vblank = armada_drm_enable_vblank, |
| 342 | .disable_vblank = armada_drm_disable_vblank, | 292 | .disable_vblank = armada_drm_disable_vblank, |
| 343 | .irq_handler = armada_drm_irq_handler, | ||
| 344 | .irq_postinstall = armada_drm_irq_postinstall, | ||
| 345 | .irq_uninstall = armada_drm_irq_uninstall, | ||
| 346 | #ifdef CONFIG_DEBUG_FS | 293 | #ifdef CONFIG_DEBUG_FS |
| 347 | .debugfs_init = armada_drm_debugfs_init, | 294 | .debugfs_init = armada_drm_debugfs_init, |
| 348 | .debugfs_cleanup = armada_drm_debugfs_cleanup, | 295 | .debugfs_cleanup = armada_drm_debugfs_cleanup, |
| @@ -362,7 +309,7 @@ static struct drm_driver armada_drm_driver = { | |||
| 362 | .desc = "Armada SoC DRM", | 309 | .desc = "Armada SoC DRM", |
| 363 | .date = "20120730", | 310 | .date = "20120730", |
| 364 | .driver_features = DRIVER_GEM | DRIVER_MODESET | | 311 | .driver_features = DRIVER_GEM | DRIVER_MODESET | |
| 365 | DRIVER_HAVE_IRQ | DRIVER_PRIME, | 312 | DRIVER_PRIME, |
| 366 | .ioctls = armada_ioctls, | 313 | .ioctls = armada_ioctls, |
| 367 | .fops = &armada_drm_fops, | 314 | .fops = &armada_drm_fops, |
| 368 | }; | 315 | }; |
