diff options
author | Dave Airlie <airlied@redhat.com> | 2019-08-27 10:10:30 +0300 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2019-08-27 10:21:04 +0300 |
commit | c87237110f2553b4200a8b3401a01198edfcf0d9 (patch) | |
tree | ac4af3166e019c5cd46c12743d8d3bbcd9391332 /drivers/gpu/drm/hisilicon | |
parent | 8c973fb611de06ce54879b4d8797bf966d3db213 (diff) | |
parent | e26ae7c0432101a924cf745b07470c8592de64cb (diff) | |
download | linux-c87237110f2553b4200a8b3401a01198edfcf0d9.tar.xz |
Merge tag 'drm-misc-next-2019-08-23' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for 5.4:
UAPI Changes:
Cross-subsystem Changes:
Core Changes:
- dma-buf: dma-fence selftests
Driver Changes:
- kirin: Various cleanups and reworks
- komeda: Add support for DT memory-regions
- meson: Rely on the compatible to detect vpu features
- omap: Implement alpha and pixel blend mode properties
- panfrost: Implement per-fd address spaces, various fixes
- rockchip: DSI DT binding rework
- fbdev: Various cleanups
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Maxime Ripard <maxime.ripard@bootlin.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190823083509.c7mduqdqjnxc7ubb@flea
Diffstat (limited to 'drivers/gpu/drm/hisilicon')
-rw-r--r-- | drivers/gpu/drm/hisilicon/kirin/Kconfig | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/hisilicon/kirin/Makefile | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c | 351 | ||||
-rw-r--r-- | drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c | 250 | ||||
-rw-r--r-- | drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h | 48 |
6 files changed, 367 insertions, 296 deletions
diff --git a/drivers/gpu/drm/hisilicon/kirin/Kconfig b/drivers/gpu/drm/hisilicon/kirin/Kconfig index 0fa29af08ad0..290553e2f6b4 100644 --- a/drivers/gpu/drm/hisilicon/kirin/Kconfig +++ b/drivers/gpu/drm/hisilicon/kirin/Kconfig @@ -5,16 +5,8 @@ config DRM_HISI_KIRIN select DRM_KMS_HELPER select DRM_GEM_CMA_HELPER select DRM_KMS_CMA_HELPER - select HISI_KIRIN_DW_DSI + select DRM_MIPI_DSI help Choose this option if you have a hisilicon Kirin chipsets(hi6220). If M is selected the module will be called kirin-drm. -config HISI_KIRIN_DW_DSI - tristate "HiSilicon Kirin specific extensions for Synopsys DW MIPI DSI" - depends on DRM_HISI_KIRIN - select DRM_MIPI_DSI - help - This selects support for HiSilicon Kirin SoC specific extensions for - the Synopsys DesignWare DSI driver. If you want to enable MIPI DSI on - hi6220 based SoC, you should selet this option. diff --git a/drivers/gpu/drm/hisilicon/kirin/Makefile b/drivers/gpu/drm/hisilicon/kirin/Makefile index c0501fa3fe53..d9323f66a7d4 100644 --- a/drivers/gpu/drm/hisilicon/kirin/Makefile +++ b/drivers/gpu/drm/hisilicon/kirin/Makefile @@ -2,6 +2,5 @@ kirin-drm-y := kirin_drm_drv.o \ kirin_drm_ade.o -obj-$(CONFIG_DRM_HISI_KIRIN) += kirin-drm.o +obj-$(CONFIG_DRM_HISI_KIRIN) += kirin-drm.o dw_drm_dsi.o -obj-$(CONFIG_HISI_KIRIN_DW_DSI) += dw_drm_dsi.o diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h b/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h index e2ac09894a6d..0da860200410 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h @@ -83,6 +83,7 @@ #define VSIZE_OFST 20 #define LDI_INT_EN 0x741C #define FRAME_END_INT_EN_OFST 1 +#define UNDERFLOW_INT_EN_OFST 2 #define LDI_CTRL 0x7420 #define BPP_OFST 3 #define DATA_GATE_EN BIT(2) diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c index 0df1afdf319d..73cd28a6ea07 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c @@ -30,19 +30,14 @@ #include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> +#include <drm/drm_gem_framebuffer_helper.h> #include "kirin_drm_drv.h" #include "kirin_ade_reg.h" -#define PRIMARY_CH ADE_CH1 /* primary plane */ #define OUT_OVLY ADE_OVLY2 /* output overlay compositor */ #define ADE_DEBUG 1 -#define to_ade_crtc(crtc) \ - container_of(crtc, struct ade_crtc, base) - -#define to_ade_plane(plane) \ - container_of(plane, struct ade_plane, base) struct ade_hw_ctx { void __iomem *base; @@ -51,36 +46,14 @@ struct ade_hw_ctx { struct clk *media_noc_clk; struct clk *ade_pix_clk; struct reset_control *reset; + struct work_struct display_reset_wq; bool power_on; int irq; -}; - -struct ade_crtc { - struct drm_crtc base; - struct ade_hw_ctx *ctx; - bool enable; - u32 out_format; -}; - -struct ade_plane { - struct drm_plane base; - void *ctx; - u8 ch; /* channel */ -}; -struct ade_data { - struct ade_crtc acrtc; - struct ade_plane aplane[ADE_CH_NUM]; - struct ade_hw_ctx ctx; + struct drm_crtc *crtc; }; -/* ade-format info: */ -struct ade_format { - u32 pixel_format; - enum ade_fb_format ade_format; -}; - -static const struct ade_format ade_formats[] = { +static const struct kirin_format ade_formats[] = { /* 16bpp RGB: */ { DRM_FORMAT_RGB565, ADE_RGB_565 }, { DRM_FORMAT_BGR565, ADE_BGR_565 }, @@ -96,7 +69,7 @@ static const struct ade_format ade_formats[] = { { DRM_FORMAT_ABGR8888, ADE_ABGR_8888 }, }; -static const u32 channel_formats1[] = { +static const u32 channel_formats[] = { /* channel 1,2,3,4 */ DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, DRM_FORMAT_RGB888, DRM_FORMAT_BGR888, DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888, @@ -104,19 +77,6 @@ static const u32 channel_formats1[] = { DRM_FORMAT_ABGR8888 }; -u32 ade_get_channel_formats(u8 ch, const u32 **formats) -{ - switch (ch) { - case ADE_CH1: - *formats = channel_formats1; - return ARRAY_SIZE(channel_formats1); - default: - DRM_ERROR("no this channel %d\n", ch); - *formats = NULL; - return 0; - } -} - /* convert from fourcc format to ade format */ static u32 ade_get_format(u32 pixel_format) { @@ -124,7 +84,7 @@ static u32 ade_get_format(u32 pixel_format) for (i = 0; i < ARRAY_SIZE(ade_formats); i++) if (ade_formats[i].pixel_format == pixel_format) - return ade_formats[i].ade_format; + return ade_formats[i].hw_format; /* not found */ DRM_ERROR("Not found pixel format!!fourcc_format= %d\n", @@ -176,14 +136,15 @@ static void ade_init(struct ade_hw_ctx *ctx) */ ade_update_bits(base + ADE_CTRL, FRM_END_START_OFST, FRM_END_START_MASK, REG_EFFECTIVE_IN_ADEEN_FRMEND); + ade_update_bits(base + LDI_INT_EN, UNDERFLOW_INT_EN_OFST, MASK(1), 1); } static bool ade_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct ade_crtc *acrtc = to_ade_crtc(crtc); - struct ade_hw_ctx *ctx = acrtc->ctx; + struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); + struct ade_hw_ctx *ctx = kcrtc->hw_ctx; adjusted_mode->clock = clk_round_rate(ctx->ade_pix_clk, mode->clock * 1000) / 1000; @@ -208,11 +169,10 @@ static void ade_set_pix_clk(struct ade_hw_ctx *ctx, adj_mode->clock = clk_get_rate(ctx->ade_pix_clk) / 1000; } -static void ade_ldi_set_mode(struct ade_crtc *acrtc, +static void ade_ldi_set_mode(struct ade_hw_ctx *ctx, struct drm_display_mode *mode, struct drm_display_mode *adj_mode) { - struct ade_hw_ctx *ctx = acrtc->ctx; void __iomem *base = ctx->base; u32 width = mode->hdisplay; u32 height = mode->vdisplay; @@ -299,9 +259,8 @@ static void ade_power_down(struct ade_hw_ctx *ctx) ctx->power_on = false; } -static void ade_set_medianoc_qos(struct ade_crtc *acrtc) +static void ade_set_medianoc_qos(struct ade_hw_ctx *ctx) { - struct ade_hw_ctx *ctx = acrtc->ctx; struct regmap *map = ctx->noc_regmap; regmap_update_bits(map, ADE0_QOSGENERATOR_MODE, @@ -317,8 +276,8 @@ static void ade_set_medianoc_qos(struct ade_crtc *acrtc) static int ade_crtc_enable_vblank(struct drm_crtc *crtc) { - struct ade_crtc *acrtc = to_ade_crtc(crtc); - struct ade_hw_ctx *ctx = acrtc->ctx; + struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); + struct ade_hw_ctx *ctx = kcrtc->hw_ctx; void __iomem *base = ctx->base; if (!ctx->power_on) @@ -332,8 +291,8 @@ static int ade_crtc_enable_vblank(struct drm_crtc *crtc) static void ade_crtc_disable_vblank(struct drm_crtc *crtc) { - struct ade_crtc *acrtc = to_ade_crtc(crtc); - struct ade_hw_ctx *ctx = acrtc->ctx; + struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); + struct ade_hw_ctx *ctx = kcrtc->hw_ctx; void __iomem *base = ctx->base; if (!ctx->power_on) { @@ -345,11 +304,21 @@ static void ade_crtc_disable_vblank(struct drm_crtc *crtc) MASK(1), 0); } +static void drm_underflow_wq(struct work_struct *work) +{ + struct ade_hw_ctx *ctx = container_of(work, struct ade_hw_ctx, + display_reset_wq); + struct drm_device *drm_dev = ctx->crtc->dev; + struct drm_atomic_state *state; + + state = drm_atomic_helper_suspend(drm_dev); + drm_atomic_helper_resume(drm_dev, state); +} + static irqreturn_t ade_irq_handler(int irq, void *data) { - struct ade_crtc *acrtc = data; - struct ade_hw_ctx *ctx = acrtc->ctx; - struct drm_crtc *crtc = &acrtc->base; + struct ade_hw_ctx *ctx = data; + struct drm_crtc *crtc = ctx->crtc; void __iomem *base = ctx->base; u32 status; @@ -362,15 +331,20 @@ static irqreturn_t ade_irq_handler(int irq, void *data) MASK(1), 1); drm_crtc_handle_vblank(crtc); } + if (status & BIT(UNDERFLOW_INT_EN_OFST)) { + ade_update_bits(base + LDI_INT_CLR, UNDERFLOW_INT_EN_OFST, + MASK(1), 1); + DRM_ERROR("LDI underflow!"); + schedule_work(&ctx->display_reset_wq); + } return IRQ_HANDLED; } -static void ade_display_enable(struct ade_crtc *acrtc) +static void ade_display_enable(struct ade_hw_ctx *ctx) { - struct ade_hw_ctx *ctx = acrtc->ctx; void __iomem *base = ctx->base; - u32 out_fmt = acrtc->out_format; + u32 out_fmt = LDI_OUT_RGB_888; /* enable output overlay compositor */ writel(ADE_ENABLE, base + ADE_OVLYX_CTL(OUT_OVLY)); @@ -483,11 +457,11 @@ static void ade_dump_regs(void __iomem *base) { } static void ade_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { - struct ade_crtc *acrtc = to_ade_crtc(crtc); - struct ade_hw_ctx *ctx = acrtc->ctx; + struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); + struct ade_hw_ctx *ctx = kcrtc->hw_ctx; int ret; - if (acrtc->enable) + if (kcrtc->enable) return; if (!ctx->power_on) { @@ -496,63 +470,63 @@ static void ade_crtc_atomic_enable(struct drm_crtc *crtc, return; } - ade_set_medianoc_qos(acrtc); - ade_display_enable(acrtc); + ade_set_medianoc_qos(ctx); + ade_display_enable(ctx); ade_dump_regs(ctx->base); drm_crtc_vblank_on(crtc); - acrtc->enable = true; + kcrtc->enable = true; } static void ade_crtc_atomic_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { - struct ade_crtc *acrtc = to_ade_crtc(crtc); - struct ade_hw_ctx *ctx = acrtc->ctx; + struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); + struct ade_hw_ctx *ctx = kcrtc->hw_ctx; - if (!acrtc->enable) + if (!kcrtc->enable) return; drm_crtc_vblank_off(crtc); ade_power_down(ctx); - acrtc->enable = false; + kcrtc->enable = false; } static void ade_crtc_mode_set_nofb(struct drm_crtc *crtc) { - struct ade_crtc *acrtc = to_ade_crtc(crtc); - struct ade_hw_ctx *ctx = acrtc->ctx; + struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); + struct ade_hw_ctx *ctx = kcrtc->hw_ctx; struct drm_display_mode *mode = &crtc->state->mode; struct drm_display_mode *adj_mode = &crtc->state->adjusted_mode; if (!ctx->power_on) (void)ade_power_up(ctx); - ade_ldi_set_mode(acrtc, mode, adj_mode); + ade_ldi_set_mode(ctx, mode, adj_mode); } static void ade_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { - struct ade_crtc *acrtc = to_ade_crtc(crtc); - struct ade_hw_ctx *ctx = acrtc->ctx; + struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); + struct ade_hw_ctx *ctx = kcrtc->hw_ctx; struct drm_display_mode *mode = &crtc->state->mode; struct drm_display_mode *adj_mode = &crtc->state->adjusted_mode; if (!ctx->power_on) (void)ade_power_up(ctx); - ade_ldi_set_mode(acrtc, mode, adj_mode); + ade_ldi_set_mode(ctx, mode, adj_mode); } static void ade_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { - struct ade_crtc *acrtc = to_ade_crtc(crtc); - struct ade_hw_ctx *ctx = acrtc->ctx; + struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); + struct ade_hw_ctx *ctx = kcrtc->hw_ctx; struct drm_pending_vblank_event *event = crtc->state->event; void __iomem *base = ctx->base; /* only crtc is enabled regs take effect */ - if (acrtc->enable) { + if (kcrtc->enable) { ade_dump_regs(base); /* flush ade registers */ writel(ADE_ENABLE, base + ADE_EN); @@ -590,35 +564,6 @@ static const struct drm_crtc_funcs ade_crtc_funcs = { .disable_vblank = ade_crtc_disable_vblank, }; -static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, - struct drm_plane *plane) -{ - struct device_node *port; - int ret; - - /* set crtc port so that - * drm_of_find_possible_crtcs call works - */ - port = of_get_child_by_name(dev->dev->of_node, "port"); - if (!port) { - DRM_ERROR("no port node found in %pOF\n", dev->dev->of_node); - return -EINVAL; - } - of_node_put(port); - crtc->port = port; - - ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, - &ade_crtc_funcs, NULL); - if (ret) { - DRM_ERROR("failed to init crtc.\n"); - return ret; - } - - drm_crtc_helper_add(crtc, &ade_crtc_helper_funcs); - - return 0; -} - static void ade_rdma_set(void __iomem *base, struct drm_framebuffer *fb, u32 ch, u32 y, u32 in_h, u32 fmt) { @@ -780,16 +725,16 @@ static void ade_compositor_routing_disable(void __iomem *base, u32 ch) /* * Typicaly, a channel looks like: DMA-->clip-->scale-->ctrans-->compositor */ -static void ade_update_channel(struct ade_plane *aplane, +static void ade_update_channel(struct kirin_plane *kplane, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, u32 src_x, u32 src_y, u32 src_w, u32 src_h) { - struct ade_hw_ctx *ctx = aplane->ctx; + struct ade_hw_ctx *ctx = kplane->hw_ctx; void __iomem *base = ctx->base; u32 fmt = ade_get_format(fb->format->format); - u32 ch = aplane->ch; + u32 ch = kplane->ch; u32 in_w; u32 in_h; @@ -813,11 +758,11 @@ static void ade_update_channel(struct ade_plane *aplane, ade_compositor_routing_set(base, ch, crtc_x, crtc_y, in_w, in_h, fmt); } -static void ade_disable_channel(struct ade_plane *aplane) +static void ade_disable_channel(struct kirin_plane *kplane) { - struct ade_hw_ctx *ctx = aplane->ctx; + struct ade_hw_ctx *ctx = kplane->hw_ctx; void __iomem *base = ctx->base; - u32 ch = aplane->ch; + u32 ch = kplane->ch; DRM_DEBUG_DRIVER("disable channel%d\n", ch + 1); @@ -879,10 +824,10 @@ static int ade_plane_atomic_check(struct drm_plane *plane, static void ade_plane_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_state) { - struct drm_plane_state *state = plane->state; - struct ade_plane *aplane = to_ade_plane(plane); + struct drm_plane_state *state = plane->state; + struct kirin_plane *kplane = to_kirin_plane(plane); - ade_update_channel(aplane, state->fb, state->crtc_x, state->crtc_y, + ade_update_channel(kplane, state->fb, state->crtc_x, state->crtc_y, state->crtc_w, state->crtc_h, state->src_x >> 16, state->src_y >> 16, state->src_w >> 16, state->src_h >> 16); @@ -891,9 +836,9 @@ static void ade_plane_atomic_update(struct drm_plane *plane, static void ade_plane_atomic_disable(struct drm_plane *plane, struct drm_plane_state *old_state) { - struct ade_plane *aplane = to_ade_plane(plane); + struct kirin_plane *kplane = to_kirin_plane(plane); - ade_disable_channel(aplane); + ade_disable_channel(kplane); } static const struct drm_plane_helper_funcs ade_plane_helper_funcs = { @@ -911,144 +856,124 @@ static struct drm_plane_funcs ade_plane_funcs = { .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, }; -static int ade_plane_init(struct drm_device *dev, struct ade_plane *aplane, - enum drm_plane_type type) -{ - const u32 *fmts; - u32 fmts_cnt; - int ret = 0; - - /* get properties */ - fmts_cnt = ade_get_channel_formats(aplane->ch, &fmts); - if (ret) - return ret; - - ret = drm_universal_plane_init(dev, &aplane->base, 1, &ade_plane_funcs, - fmts, fmts_cnt, NULL, type, NULL); - if (ret) { - DRM_ERROR("fail to init plane, ch=%d\n", aplane->ch); - return ret; - } - - drm_plane_helper_add(&aplane->base, &ade_plane_helper_funcs); - - return 0; -} - -static int ade_dts_parse(struct platform_device *pdev, struct ade_hw_ctx *ctx) +static void *ade_hw_ctx_alloc(struct platform_device *pdev, + struct drm_crtc *crtc) { struct resource *res; struct device *dev = &pdev->dev; struct device_node *np = pdev->dev.of_node; + struct ade_hw_ctx *ctx = NULL; + int ret; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + DRM_ERROR("failed to alloc ade_hw_ctx\n"); + return ERR_PTR(-ENOMEM); + } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ctx->base = devm_ioremap_resource(dev, res); if (IS_ERR(ctx->base)) { DRM_ERROR("failed to remap ade io base\n"); - return PTR_ERR(ctx->base); + return ERR_PTR(-EIO); } ctx->reset = devm_reset_control_get(dev, NULL); if (IS_ERR(ctx->reset)) - return PTR_ERR(ctx->reset); + return ERR_PTR(-ENODEV); ctx->noc_regmap = syscon_regmap_lookup_by_phandle(np, "hisilicon,noc-syscon"); if (IS_ERR(ctx->noc_regmap)) { DRM_ERROR("failed to get noc regmap\n"); - return PTR_ERR(ctx->noc_regmap); + return ERR_PTR(-ENODEV); } ctx->irq = platform_get_irq(pdev, 0); if (ctx->irq < 0) { DRM_ERROR("failed to get irq\n"); - return -ENODEV; + return ERR_PTR(-ENODEV); } ctx->ade_core_clk = devm_clk_get(dev, "clk_ade_core"); if (IS_ERR(ctx->ade_core_clk)) { DRM_ERROR("failed to parse clk ADE_CORE\n"); - return PTR_ERR(ctx->ade_core_clk); + return ERR_PTR(-ENODEV); } ctx->media_noc_clk = devm_clk_get(dev, "clk_codec_jpeg"); if (IS_ERR(ctx->media_noc_clk)) { DRM_ERROR("failed to parse clk CODEC_JPEG\n"); - return PTR_ERR(ctx->media_noc_clk); + return ERR_PTR(-ENODEV); } ctx->ade_pix_clk = devm_clk_get(dev, "clk_ade_pix"); if (IS_ERR(ctx->ade_pix_clk)) { DRM_ERROR("failed to parse clk ADE_PIX\n"); - return PTR_ERR(ctx->ade_pix_clk); + return ERR_PTR(-ENODEV); } - return 0; -} - -static int ade_drm_init(struct platform_device *pdev) -{ - struct drm_device *dev = platform_get_drvdata(pdev); - struct ade_data *ade; - struct ade_hw_ctx *ctx; - struct ade_crtc *acrtc; - struct ade_plane *aplane; - enum drm_plane_type type; - int ret; - int i; - - ade = devm_kzalloc(dev->dev, sizeof(*ade), GFP_KERNEL); - if (!ade) { - DRM_ERROR("failed to alloc ade_data\n"); - return -ENOMEM; - } - platform_set_drvdata(pdev, ade); - - ctx = &ade->ctx; - acrtc = &ade->acrtc; - acrtc->ctx = ctx; - acrtc->out_format = LDI_OUT_RGB_888; - - ret = ade_dts_parse(pdev, ctx); - if (ret) - return ret; - - /* - * plane init - * TODO: Now only support primary plane, overlay planes - * need to do. - */ - for (i = 0; i < ADE_CH_NUM; i++) { - aplane = &ade->aplane[i]; - aplane->ch = i; - aplane->ctx = ctx; - type = i == PRIMARY_CH ? DRM_PLANE_TYPE_PRIMARY : - DRM_PLANE_TYPE_OVERLAY; - - ret = ade_plane_init(dev, aplane, type); - if (ret) - return ret; - } - - /* crtc init */ - ret = ade_crtc_init(dev, &acrtc->base, &ade->aplane[PRIMARY_CH].base); - if (ret) - return ret; - /* vblank irq init */ - ret = devm_request_irq(dev->dev, ctx->irq, ade_irq_handler, - IRQF_SHARED, dev->driver->name, acrtc); + ret = devm_request_irq(dev, ctx->irq, ade_irq_handler, + IRQF_SHARED, dev->driver->name, ctx); if (ret) - return ret; + return ERR_PTR(-EIO); - return 0; + INIT_WORK(&ctx->display_reset_wq, drm_underflow_wq); + ctx->crtc = crtc; + + return ctx; } -static void ade_drm_cleanup(struct platform_device *pdev) +static void ade_hw_ctx_cleanup(void *hw_ctx) { } -const struct kirin_dc_ops ade_dc_ops = { - .init = ade_drm_init, - .cleanup = ade_drm_cleanup +static const struct drm_mode_config_funcs ade_mode_config_funcs = { + .fb_create = drm_gem_fb_create, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, + +}; + +DEFINE_DRM_GEM_CMA_FOPS(ade_fops); + +static struct drm_driver ade_driver = { + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, + .fops = &ade_fops, + .gem_free_object_unlocked = drm_gem_cma_free_object, + .gem_vm_ops = &drm_gem_cma_vm_ops, + .dumb_create = drm_gem_cma_dumb_create_internal, + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, + .gem_prime_vmap = drm_gem_cma_prime_vmap, + .gem_prime_vunmap = drm_gem_cma_prime_vunmap, + .gem_prime_mmap = drm_gem_cma_prime_mmap, + + .name = "kirin", + .desc = "Hisilicon Kirin620 SoC DRM Driver", + .date = "20150718", + .major = 1, + .minor = 0, +}; + +struct kirin_drm_data ade_driver_data = { + .register_connects = false, + .num_planes = ADE_CH_NUM, + .prim_plane = ADE_CH1, + .channel_formats = channel_formats, + .channel_formats_cnt = ARRAY_SIZE(channel_formats), + .config_max_width = 2048, + .config_max_height = 2048, + .driver = &ade_driver, + .crtc_helper_funcs = &ade_crtc_helper_funcs, + .crtc_funcs = &ade_crtc_funcs, + .plane_helper_funcs = &ade_plane_helper_funcs, + .plane_funcs = &ade_plane_funcs, + .mode_config_funcs = &ade_mode_config_funcs, + + .alloc_hw_ctx = ade_hw_ctx_alloc, + .cleanup_hw_ctx = ade_hw_ctx_cleanup, }; diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c index 204c94c01e3d..d3145ae877d7 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c @@ -29,46 +29,146 @@ #include "kirin_drm_drv.h" -static struct kirin_dc_ops *dc_ops; +#define KIRIN_MAX_PLANE 2 -static int kirin_drm_kms_cleanup(struct drm_device *dev) +struct kirin_drm_private { + struct kirin_crtc crtc; + struct kirin_plane planes[KIRIN_MAX_PLANE]; + void *hw_ctx; +}; + +static int kirin_drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, + struct drm_plane *plane, + const struct kirin_drm_data *driver_data) { - drm_kms_helper_poll_fini(dev); - dc_ops->cleanup(to_platform_device(dev->dev)); - drm_mode_config_cleanup(dev); + struct device_node *port; + int ret; + + /* set crtc port so that + * drm_of_find_possible_crtcs call works + */ + port = of_get_child_by_name(dev->dev->of_node, "port"); + if (!port) { + DRM_ERROR("no port node found in %pOF\n", dev->dev->of_node); + return -EINVAL; + } + of_node_put(port); + crtc->port = port; + + ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, + driver_data->crtc_funcs, NULL); + if (ret) { + DRM_ERROR("failed to init crtc.\n"); + return ret; + } + + drm_crtc_helper_add(crtc, driver_data->crtc_helper_funcs); return 0; } -static const struct drm_mode_config_funcs kirin_drm_mode_config_funcs = { - .fb_create = drm_gem_fb_create, - .atomic_check = drm_atomic_helper_check, - .atomic_commit = drm_atomic_helper_commit, -}; +static int kirin_drm_plane_init(struct drm_device *dev, struct drm_plane *plane, + enum drm_plane_type type, + const struct kirin_drm_data *data) +{ + int ret = 0; + + ret = drm_universal_plane_init(dev, plane, 1, data->plane_funcs, + data->channel_formats, + data->channel_formats_cnt, + NULL, type, NULL); + if (ret) { + DRM_ERROR("fail to init plane, ch=%d\n", 0); + return ret; + } + + drm_plane_helper_add(plane, data->plane_helper_funcs); -static void kirin_drm_mode_config_init(struct drm_device *dev) + return 0; +} + +static void kirin_drm_private_cleanup(struct drm_device *dev) { - dev->mode_config.min_width = 0; - dev->mode_config.min_height = 0; + struct kirin_drm_private *kirin_priv = dev->dev_private; + struct kirin_drm_data *data; - dev->mode_config.max_width = 2048; - dev->mode_config.max_height = 2048; + data = (struct kirin_drm_data *)of_device_get_match_data(dev->dev); + if (data->cleanup_hw_ctx) + data->cleanup_hw_ctx(kirin_priv->hw_ctx); - dev->mode_config.funcs = &kirin_drm_mode_config_funcs; + devm_kfree(dev->dev, kirin_priv); + dev->dev_private = NULL; } -static int kirin_drm_kms_init(struct drm_device *dev) +static int kirin_drm_private_init(struct drm_device *dev, + const struct kirin_drm_data *driver_data) { + struct platform_device *pdev = to_platform_device(dev->dev); + struct kirin_drm_private *kirin_priv; + struct drm_plane *prim_plane; + enum drm_plane_type type; + void *ctx; int ret; + u32 ch; + + kirin_priv = devm_kzalloc(dev->dev, sizeof(*kirin_priv), GFP_KERNEL); + if (!kirin_priv) { + DRM_ERROR("failed to alloc kirin_drm_private\n"); + return -ENOMEM; + } + + ctx = driver_data->alloc_hw_ctx(pdev, &kirin_priv->crtc.base); + if (IS_ERR(ctx)) { + DRM_ERROR("failed to initialize kirin_priv hw ctx\n"); + return -EINVAL; + } + kirin_priv->hw_ctx = ctx; + + /* + * plane init + * TODO: Now only support primary plane, overlay planes + * need to do. + */ + for (ch = 0; ch < driver_data->num_planes; ch++) { + if (ch == driver_data->prim_plane) + type = DRM_PLANE_TYPE_PRIMARY; + else + type = DRM_PLANE_TYPE_OVERLAY; + ret = kirin_drm_plane_init(dev, &kirin_priv->planes[ch].base, + type, driver_data); + if (ret) + return ret; + kirin_priv->planes[ch].ch = ch; + kirin_priv->planes[ch].hw_ctx = ctx; + } - dev_set_drvdata(dev->dev, dev); + /* crtc init */ + prim_plane = &kirin_priv->planes[driver_data->prim_plane].base; + ret = kirin_drm_crtc_init(dev, &kirin_priv->crtc.base, + prim_plane, driver_data); + if (ret) + return ret; + kirin_priv->crtc.hw_ctx = ctx; + dev->dev_private = kirin_priv; + + return 0; +} + +static int kirin_drm_kms_init(struct drm_device *dev, + const struct kirin_drm_data *driver_data) +{ + int ret; /* dev->mode_config initialization */ drm_mode_config_init(dev); - kirin_drm_mode_config_init(dev); + dev->mode_config.min_width = 0; + dev->mode_config.min_height = 0; + dev->mode_config.max_width = driver_data->config_max_width; + dev->mode_config.max_height = driver_data->config_max_width; + dev->mode_config.funcs = driver_data->mode_config_funcs; /* display controller init */ - ret = dc_ops->init(to_platform_device(dev->dev)); + ret = kirin_drm_private_init(dev, driver_data); if (ret) goto err_mode_config_cleanup; @@ -76,7 +176,7 @@ static int kirin_drm_kms_init(struct drm_device *dev) ret = component_bind_all(dev->dev, dev); if (ret) { DRM_ERROR("failed to bind all component.\n"); - goto err_dc_cleanup; + goto err_private_cleanup; } /* vblank init */ @@ -98,62 +198,78 @@ static int kirin_drm_kms_init(struct drm_device *dev) err_unbind_all: component_unbind_all(dev->dev, dev); -err_dc_cleanup: - dc_ops->cleanup(to_platform_device(dev->dev)); +err_private_cleanup: + kirin_drm_private_cleanup(dev); err_mode_config_cleanup: drm_mode_config_cleanup(dev); - return ret; } -DEFINE_DRM_GEM_CMA_FOPS(kirin_drm_fops); - -static int kirin_gem_cma_dumb_create(struct drm_file *file, - struct drm_device *dev, - struct drm_mode_create_dumb *args) +static int compare_of(struct device *dev, void *data) { - return drm_gem_cma_dumb_create_internal(file, dev, args); + return dev->of_node == data; } -static struct drm_driver kirin_drm_driver = { - .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, - .fops = &kirin_drm_fops, - - .gem_free_object_unlocked = drm_gem_cma_free_object, - .gem_vm_ops = &drm_gem_cma_vm_ops, - .dumb_create = kirin_gem_cma_dumb_create, - - .prime_handle_to_fd = drm_gem_prime_handle_to_fd, - .prime_fd_to_handle = drm_gem_prime_fd_to_handle, - .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, - .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, - .gem_prime_vmap = drm_gem_cma_prime_vmap, - .gem_prime_vunmap = drm_gem_cma_prime_vunmap, - .gem_prime_mmap = drm_gem_cma_prime_mmap, - - .name = "kirin", - .desc = "Hisilicon Kirin SoCs' DRM Driver", - .date = "20150718", - .major = 1, - .minor = 0, -}; +static int kirin_drm_kms_cleanup(struct drm_device *dev) +{ + drm_kms_helper_poll_fini(dev); + kirin_drm_private_cleanup(dev); + drm_mode_config_cleanup(dev); -static int compare_of(struct device *dev, void *data) + return 0; +} + +static int kirin_drm_connectors_register(struct drm_device *dev) { - return dev->of_node == data; + struct drm_connector *connector; + struct drm_connector *failed_connector; + struct drm_connector_list_iter conn_iter; + int ret; + + mutex_lock(&dev->mode_config.mutex); + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + ret = drm_connector_register(connector); + if (ret) { + failed_connector = connector; + goto err; + } + } + drm_connector_list_iter_end(&conn_iter); + mutex_unlock(&dev->mode_config.mutex); + + return 0; + +err: + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + if (failed_connector == connector) + break; + drm_connector_unregister(connector); + } + drm_connector_list_iter_end(&conn_iter); + mutex_unlock(&dev->mode_config.mutex); + + return ret; } static int kirin_drm_bind(struct device *dev) { - struct drm_driver *driver = &kirin_drm_driver; + struct kirin_drm_data *driver_data; struct drm_device *drm_dev; int ret; - drm_dev = drm_dev_alloc(driver, dev); + driver_data = (struct kirin_drm_data *)of_device_get_match_data(dev); + if (!driver_data) + return -EINVAL; + + drm_dev = drm_dev_alloc(driver_data->driver, dev); if (IS_ERR(drm_dev)) return PTR_ERR(drm_dev); + dev_set_drvdata(dev, drm_dev); - ret = kirin_drm_kms_init(drm_dev); + /* display controller init */ + ret = kirin_drm_kms_init(drm_dev, driver_data); if (ret) goto err_drm_dev_put; @@ -163,8 +279,17 @@ static int kirin_drm_bind(struct device *dev) drm_fbdev_generic_setup(drm_dev, 32); + /* connectors should be registered after drm device register */ + if (driver_data->register_connects) { + ret = kirin_drm_connectors_register(drm_dev); + if (ret) + goto err_drm_dev_unregister; + } + return 0; +err_drm_dev_unregister: + drm_dev_unregister(drm_dev); err_kms_cleanup: kirin_drm_kms_cleanup(drm_dev); err_drm_dev_put: @@ -194,12 +319,6 @@ static int kirin_drm_platform_probe(struct platform_device *pdev) struct component_match *match = NULL; struct device_node *remote; - dc_ops = (struct kirin_dc_ops *)of_device_get_match_data(dev); - if (!dc_ops) { - DRM_ERROR("failed to get dt id data\n"); - return -EINVAL; - } - remote = of_graph_get_remote_node(np, 0, 0); if (!remote) return -ENODEV; @@ -208,20 +327,17 @@ static int kirin_drm_platform_probe(struct platform_device *pdev) of_node_put(remote); return component_master_add_with_match(dev, &kirin_drm_ops, match); - - return 0; } static int kirin_drm_platform_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &kirin_drm_ops); - dc_ops = NULL; return 0; } static const struct of_device_id kirin_drm_dt_ids[] = { { .compatible = "hisilicon,hi6220-ade", - .data = &ade_dc_ops, + .data = &ade_driver_data, }, { /* end node */ }, }; diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h index 22d1291668cd..4d5c05a24065 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h @@ -7,14 +7,52 @@ #ifndef __KIRIN_DRM_DRV_H__ #define __KIRIN_DRM_DRV_H__ -#define MAX_CRTC 2 +#define to_kirin_crtc(crtc) \ + container_of(crtc, struct kirin_crtc, base) + +#define to_kirin_plane(plane) \ + container_of(plane, struct kirin_plane, base) + +/* kirin-format translate table */ +struct kirin_format { + u32 pixel_format; + u32 hw_format; +}; + +struct kirin_crtc { + struct drm_crtc base; + void *hw_ctx; + bool enable; +}; + +struct kirin_plane { + struct drm_plane base; + void *hw_ctx; + u32 ch; +}; /* display controller init/cleanup ops */ -struct kirin_dc_ops { - int (*init)(struct platform_device *pdev); - void (*cleanup)(struct platform_device *pdev); +struct kirin_drm_data { + const u32 *channel_formats; + u32 channel_formats_cnt; + int config_max_width; + int config_max_height; + bool register_connects; + u32 num_planes; + u32 prim_plane; + + struct drm_driver *driver; + const struct drm_crtc_helper_funcs *crtc_helper_funcs; + const struct drm_crtc_funcs *crtc_funcs; + const struct drm_plane_helper_funcs *plane_helper_funcs; + const struct drm_plane_funcs *plane_funcs; + const struct drm_mode_config_funcs *mode_config_funcs; + + void *(*alloc_hw_ctx)(struct platform_device *pdev, + struct drm_crtc *crtc); + void (*cleanup_hw_ctx)(void *hw_ctx); }; -extern const struct kirin_dc_ops ade_dc_ops; +extern struct kirin_drm_data ade_driver_data; #endif /* __KIRIN_DRM_DRV_H__ */ |