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
This commit is contained in:
Dave Airlie
2019-08-27 17:10:30 +10:00
57 ha cambiato i file con 1681 aggiunte e 675 eliminazioni

Vedi File

@@ -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.

Vedi File

@@ -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

Vedi File

@@ -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)

Vedi File

@@ -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 drm_crtc *crtc;
};
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;
};
/* 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,
};

Vedi File

@@ -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 void kirin_drm_mode_config_init(struct drm_device *dev)
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)
{
dev->mode_config.min_width = 0;
dev->mode_config.min_height = 0;
int ret = 0;
dev->mode_config.max_width = 2048;
dev->mode_config.max_height = 2048;
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;
}
dev->mode_config.funcs = &kirin_drm_mode_config_funcs;
drm_plane_helper_add(plane, data->plane_helper_funcs);
return 0;
}
static int kirin_drm_kms_init(struct drm_device *dev)
static void kirin_drm_private_cleanup(struct drm_device *dev)
{
struct kirin_drm_private *kirin_priv = dev->dev_private;
struct kirin_drm_data *data;
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);
devm_kfree(dev->dev, kirin_priv);
dev->dev_private = NULL;
}
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;
}
/* 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_set_drvdata(dev->dev, dev);
/* 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)
{
return drm_gem_cma_dumb_create_internal(file, dev, args);
}
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 compare_of(struct device *dev, void *data)
{
return dev->of_node == data;
}
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);
return 0;
}
static int kirin_drm_connectors_register(struct drm_device *dev)
{
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 */ },
};

Vedi File

@@ -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)
/* display controller init/cleanup ops */
struct kirin_dc_ops {
int (*init)(struct platform_device *pdev);
void (*cleanup)(struct platform_device *pdev);
#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;
};
extern const struct kirin_dc_ops ade_dc_ops;
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_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 struct kirin_drm_data ade_driver_data;
#endif /* __KIRIN_DRM_DRV_H__ */