linux/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c

847 lines
19 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Traphandler
* Copyright (C) 2014 Free Electrons
* Copyright (C) 2014 Atmel
*
* Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
* Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
*/
#include <linux/clk.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/mfd/atmel-hlcdc.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fbdev_dma.h>
drm/gem: rename GEM CMA helpers to GEM DMA helpers Rename "GEM CMA" helpers to "GEM DMA" helpers - considering the hierarchy of APIs (mm/cma -> dma -> gem dma) calling them "GEM DMA" seems to be more applicable. Besides that, commit e57924d4ae80 ("drm/doc: Task to rename CMA helpers") requests to rename the CMA helpers and implies that people seem to be confused about the naming. In order to do this renaming the following script was used: ``` #!/bin/bash DIRS="drivers/gpu include/drm Documentation/gpu" REGEX_SYM_UPPER="[0-9A-Z_\-]" REGEX_SYM_LOWER="[0-9a-z_\-]" REGEX_GREP_UPPER="(${REGEX_SYM_UPPER}*)(GEM)_CMA_(${REGEX_SYM_UPPER}*)" REGEX_GREP_LOWER="(${REGEX_SYM_LOWER}*)(gem)_cma_(${REGEX_SYM_LOWER}*)" REGEX_SED_UPPER="s/${REGEX_GREP_UPPER}/\1\2_DMA_\3/g" REGEX_SED_LOWER="s/${REGEX_GREP_LOWER}/\1\2_dma_\3/g" # Find all upper case 'CMA' symbols and replace them with 'DMA'. for ff in $(grep -REHl "${REGEX_GREP_UPPER}" $DIRS) do sed -i -E "$REGEX_SED_UPPER" $ff done # Find all lower case 'cma' symbols and replace them with 'dma'. for ff in $(grep -REHl "${REGEX_GREP_LOWER}" $DIRS) do sed -i -E "$REGEX_SED_LOWER" $ff done # Replace all occurrences of 'CMA' / 'cma' in comments and # documentation files with 'DMA' / 'dma'. for ff in $(grep -RiHl " cma " $DIRS) do sed -i -E "s/ cma / dma /g" $ff sed -i -E "s/ CMA / DMA /g" $ff done # Rename all 'cma_obj's to 'dma_obj'. for ff in $(grep -RiHl "cma_obj" $DIRS) do sed -i -E "s/cma_obj/dma_obj/g" $ff done ``` Only a few more manual modifications were needed, e.g. reverting the following modifications in some DRM Kconfig files - select CMA if HAVE_DMA_CONTIGUOUS + select DMA if HAVE_DMA_CONTIGUOUS as well as manually picking the occurrences of 'CMA'/'cma' in comments and documentation which relate to "GEM CMA", but not "FB CMA". Also drivers/gpu/drm/Makefile was fixed up manually after renaming drm_gem_cma_helper.c to drm_gem_dma_helper.c. This patch is compile-time tested building a x86_64 kernel with `make allyesconfig && make drivers/gpu/drm`. Acked-by: Sam Ravnborg <sam@ravnborg.org> Acked-by: Thomas Zimmermann <tzimmermann@suse.de> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Danilo Krummrich <dakr@redhat.com> Reviewed-by: Liviu Dudau <liviu.dudau@arm.com> #drivers/gpu/drm/arm Signed-off-by: Sam Ravnborg <sam@ravnborg.org> Link: https://patchwork.freedesktop.org/patch/msgid/20220802000405.949236-4-dakr@redhat.com
2022-08-02 02:04:03 +02:00
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_module.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
#include "atmel_hlcdc_dc.h"
#define ATMEL_HLCDC_LAYER_IRQS_OFFSET 8
static const struct atmel_hlcdc_layer_desc atmel_hlcdc_at91sam9n12_layers[] = {
{
.name = "base",
.formats = &atmel_hlcdc_plane_rgb_formats,
.regs_offset = 0x40,
.id = 0,
.type = ATMEL_HLCDC_BASE_LAYER,
.cfgs_offset = 0x2c,
.layout = {
.xstride = { 2 },
.default_color = 3,
.general_config = 4,
},
.clut_offset = 0x400,
},
};
static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_at91sam9n12 = {
.min_width = 0,
.min_height = 0,
.max_width = 1280,
.max_height = 860,
.max_spw = 0x3f,
.max_vpw = 0x3f,
.max_hpw = 0xff,
.conflicting_output_formats = true,
.nlayers = ARRAY_SIZE(atmel_hlcdc_at91sam9n12_layers),
.layers = atmel_hlcdc_at91sam9n12_layers,
};
static const struct atmel_hlcdc_layer_desc atmel_hlcdc_at91sam9x5_layers[] = {
{
.name = "base",
.formats = &atmel_hlcdc_plane_rgb_formats,
.regs_offset = 0x40,
.id = 0,
.type = ATMEL_HLCDC_BASE_LAYER,
.cfgs_offset = 0x2c,
.layout = {
.xstride = { 2 },
.default_color = 3,
.general_config = 4,
.disc_pos = 5,
.disc_size = 6,
},
.clut_offset = 0x400,
},
{
.name = "overlay1",
.formats = &atmel_hlcdc_plane_rgb_formats,
.regs_offset = 0x100,
.id = 1,
.type = ATMEL_HLCDC_OVERLAY_LAYER,
.cfgs_offset = 0x2c,
.layout = {
.pos = 2,
.size = 3,
.xstride = { 4 },
.pstride = { 5 },
.default_color = 6,
.chroma_key = 7,
.chroma_key_mask = 8,
.general_config = 9,
},
.clut_offset = 0x800,
},
{
.name = "high-end-overlay",
.formats = &atmel_hlcdc_plane_rgb_and_yuv_formats,
.regs_offset = 0x280,
.id = 2,
.type = ATMEL_HLCDC_OVERLAY_LAYER,
.cfgs_offset = 0x4c,
.layout = {
.pos = 2,
.size = 3,
.memsize = 4,
.xstride = { 5, 7 },
.pstride = { 6, 8 },
.default_color = 9,
.chroma_key = 10,
.chroma_key_mask = 11,
.general_config = 12,
.scaler_config = 13,
.csc = 14,
},
.clut_offset = 0x1000,
},
{
.name = "cursor",
.formats = &atmel_hlcdc_plane_rgb_formats,
.regs_offset = 0x340,
.id = 3,
.type = ATMEL_HLCDC_CURSOR_LAYER,
.max_width = 128,
.max_height = 128,
.cfgs_offset = 0x2c,
.layout = {
.pos = 2,
.size = 3,
.xstride = { 4 },
.default_color = 6,
.chroma_key = 7,
.chroma_key_mask = 8,
.general_config = 9,
},
.clut_offset = 0x1400,
},
};
static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_at91sam9x5 = {
.min_width = 0,
.min_height = 0,
.max_width = 800,
.max_height = 600,
.max_spw = 0x3f,
.max_vpw = 0x3f,
.max_hpw = 0xff,
.conflicting_output_formats = true,
.nlayers = ARRAY_SIZE(atmel_hlcdc_at91sam9x5_layers),
.layers = atmel_hlcdc_at91sam9x5_layers,
};
static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = {
{
.name = "base",
.formats = &atmel_hlcdc_plane_rgb_formats,
.regs_offset = 0x40,
.id = 0,
.type = ATMEL_HLCDC_BASE_LAYER,
.cfgs_offset = 0x2c,
.layout = {
.xstride = { 2 },
.default_color = 3,
.general_config = 4,
.disc_pos = 5,
.disc_size = 6,
},
.clut_offset = 0x600,
},
{
.name = "overlay1",
.formats = &atmel_hlcdc_plane_rgb_formats,
.regs_offset = 0x140,
.id = 1,
.type = ATMEL_HLCDC_OVERLAY_LAYER,
.cfgs_offset = 0x2c,
.layout = {
.pos = 2,
.size = 3,
.xstride = { 4 },
.pstride = { 5 },
.default_color = 6,
.chroma_key = 7,
.chroma_key_mask = 8,
.general_config = 9,
},
.clut_offset = 0xa00,
},
{
.name = "overlay2",
.formats = &atmel_hlcdc_plane_rgb_formats,
.regs_offset = 0x240,
.id = 2,
.type = ATMEL_HLCDC_OVERLAY_LAYER,
.cfgs_offset = 0x2c,
.layout = {
.pos = 2,
.size = 3,
.xstride = { 4 },
.pstride = { 5 },
.default_color = 6,
.chroma_key = 7,
.chroma_key_mask = 8,
.general_config = 9,
},
.clut_offset = 0xe00,
},
{
.name = "high-end-overlay",
.formats = &atmel_hlcdc_plane_rgb_and_yuv_formats,
.regs_offset = 0x340,
.id = 3,
.type = ATMEL_HLCDC_OVERLAY_LAYER,
.cfgs_offset = 0x4c,
.layout = {
.pos = 2,
.size = 3,
.memsize = 4,
.xstride = { 5, 7 },
.pstride = { 6, 8 },
.default_color = 9,
.chroma_key = 10,
.chroma_key_mask = 11,
.general_config = 12,
.scaler_config = 13,
.phicoeffs = {
.x = 17,
.y = 33,
},
.csc = 14,
},
.clut_offset = 0x1200,
},
{
.name = "cursor",
.formats = &atmel_hlcdc_plane_rgb_formats,
.regs_offset = 0x440,
.id = 4,
.type = ATMEL_HLCDC_CURSOR_LAYER,
.max_width = 128,
.max_height = 128,
.cfgs_offset = 0x2c,
.layout = {
.pos = 2,
.size = 3,
.xstride = { 4 },
.pstride = { 5 },
.default_color = 6,
.chroma_key = 7,
.chroma_key_mask = 8,
.general_config = 9,
.scaler_config = 13,
},
.clut_offset = 0x1600,
},
};
static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_sama5d3 = {
.min_width = 0,
.min_height = 0,
.max_width = 2048,
.max_height = 2048,
.max_spw = 0x3f,
.max_vpw = 0x3f,
.max_hpw = 0x1ff,
.conflicting_output_formats = true,
.nlayers = ARRAY_SIZE(atmel_hlcdc_sama5d3_layers),
.layers = atmel_hlcdc_sama5d3_layers,
};
static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d4_layers[] = {
{
.name = "base",
.formats = &atmel_hlcdc_plane_rgb_formats,
.regs_offset = 0x40,
.id = 0,
.type = ATMEL_HLCDC_BASE_LAYER,
.cfgs_offset = 0x2c,
.layout = {
.xstride = { 2 },
.default_color = 3,
.general_config = 4,
.disc_pos = 5,
.disc_size = 6,
},
.clut_offset = 0x600,
},
{
.name = "overlay1",
.formats = &atmel_hlcdc_plane_rgb_formats,
.regs_offset = 0x140,
.id = 1,
.type = ATMEL_HLCDC_OVERLAY_LAYER,
.cfgs_offset = 0x2c,
.layout = {
.pos = 2,
.size = 3,
.xstride = { 4 },
.pstride = { 5 },
.default_color = 6,
.chroma_key = 7,
.chroma_key_mask = 8,
.general_config = 9,
},
.clut_offset = 0xa00,
},
{
.name = "overlay2",
.formats = &atmel_hlcdc_plane_rgb_formats,
.regs_offset = 0x240,
.id = 2,
.type = ATMEL_HLCDC_OVERLAY_LAYER,
.cfgs_offset = 0x2c,
.layout = {
.pos = 2,
.size = 3,
.xstride = { 4 },
.pstride = { 5 },
.default_color = 6,
.chroma_key = 7,
.chroma_key_mask = 8,
.general_config = 9,
},
.clut_offset = 0xe00,
},
{
.name = "high-end-overlay",
.formats = &atmel_hlcdc_plane_rgb_and_yuv_formats,
.regs_offset = 0x340,
.id = 3,
.type = ATMEL_HLCDC_OVERLAY_LAYER,
.cfgs_offset = 0x4c,
.layout = {
.pos = 2,
.size = 3,
.memsize = 4,
.xstride = { 5, 7 },
.pstride = { 6, 8 },
.default_color = 9,
.chroma_key = 10,
.chroma_key_mask = 11,
.general_config = 12,
.scaler_config = 13,
.phicoeffs = {
.x = 17,
.y = 33,
},
.csc = 14,
},
.clut_offset = 0x1200,
},
};
static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_sama5d4 = {
.min_width = 0,
.min_height = 0,
.max_width = 2048,
.max_height = 2048,
.max_spw = 0xff,
.max_vpw = 0xff,
.max_hpw = 0x3ff,
.nlayers = ARRAY_SIZE(atmel_hlcdc_sama5d4_layers),
.layers = atmel_hlcdc_sama5d4_layers,
};
static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sam9x60_layers[] = {
{
.name = "base",
.formats = &atmel_hlcdc_plane_rgb_formats,
.regs_offset = 0x60,
.id = 0,
.type = ATMEL_HLCDC_BASE_LAYER,
.cfgs_offset = 0x2c,
.layout = {
.xstride = { 2 },
.default_color = 3,
.general_config = 4,
.disc_pos = 5,
.disc_size = 6,
},
.clut_offset = 0x600,
},
{
.name = "overlay1",
.formats = &atmel_hlcdc_plane_rgb_formats,
.regs_offset = 0x160,
.id = 1,
.type = ATMEL_HLCDC_OVERLAY_LAYER,
.cfgs_offset = 0x2c,
.layout = {
.pos = 2,
.size = 3,
.xstride = { 4 },
.pstride = { 5 },
.default_color = 6,
.chroma_key = 7,
.chroma_key_mask = 8,
.general_config = 9,
},
.clut_offset = 0xa00,
},
{
.name = "overlay2",
.formats = &atmel_hlcdc_plane_rgb_formats,
.regs_offset = 0x260,
.id = 2,
.type = ATMEL_HLCDC_OVERLAY_LAYER,
.cfgs_offset = 0x2c,
.layout = {
.pos = 2,
.size = 3,
.xstride = { 4 },
.pstride = { 5 },
.default_color = 6,
.chroma_key = 7,
.chroma_key_mask = 8,
.general_config = 9,
},
.clut_offset = 0xe00,
},
{
.name = "high-end-overlay",
.formats = &atmel_hlcdc_plane_rgb_and_yuv_formats,
.regs_offset = 0x360,
.id = 3,
.type = ATMEL_HLCDC_OVERLAY_LAYER,
.cfgs_offset = 0x4c,
.layout = {
.pos = 2,
.size = 3,
.memsize = 4,
.xstride = { 5, 7 },
.pstride = { 6, 8 },
.default_color = 9,
.chroma_key = 10,
.chroma_key_mask = 11,
.general_config = 12,
.scaler_config = 13,
.phicoeffs = {
.x = 17,
.y = 33,
},
.csc = 14,
},
.clut_offset = 0x1200,
},
};
static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_sam9x60 = {
.min_width = 0,
.min_height = 0,
.max_width = 2048,
.max_height = 2048,
.max_spw = 0xff,
.max_vpw = 0xff,
.max_hpw = 0x3ff,
.fixed_clksrc = true,
.nlayers = ARRAY_SIZE(atmel_hlcdc_sam9x60_layers),
.layers = atmel_hlcdc_sam9x60_layers,
};
static const struct of_device_id atmel_hlcdc_of_match[] = {
{
.compatible = "atmel,at91sam9n12-hlcdc",
.data = &atmel_hlcdc_dc_at91sam9n12,
},
{
.compatible = "atmel,at91sam9x5-hlcdc",
.data = &atmel_hlcdc_dc_at91sam9x5,
},
{
.compatible = "atmel,sama5d2-hlcdc",
.data = &atmel_hlcdc_dc_sama5d4,
},
{
.compatible = "atmel,sama5d3-hlcdc",
.data = &atmel_hlcdc_dc_sama5d3,
},
{
.compatible = "atmel,sama5d4-hlcdc",
.data = &atmel_hlcdc_dc_sama5d4,
},
{
.compatible = "microchip,sam9x60-hlcdc",
.data = &atmel_hlcdc_dc_sam9x60,
},
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, atmel_hlcdc_of_match);
enum drm_mode_status
atmel_hlcdc_dc_mode_valid(struct atmel_hlcdc_dc *dc,
const struct drm_display_mode *mode)
{
int vfront_porch = mode->vsync_start - mode->vdisplay;
int vback_porch = mode->vtotal - mode->vsync_end;
int vsync_len = mode->vsync_end - mode->vsync_start;
int hfront_porch = mode->hsync_start - mode->hdisplay;
int hback_porch = mode->htotal - mode->hsync_end;
int hsync_len = mode->hsync_end - mode->hsync_start;
if (hsync_len > dc->desc->max_spw + 1 || hsync_len < 1)
return MODE_HSYNC;
if (vsync_len > dc->desc->max_spw + 1 || vsync_len < 1)
return MODE_VSYNC;
if (hfront_porch > dc->desc->max_hpw + 1 || hfront_porch < 1 ||
hback_porch > dc->desc->max_hpw + 1 || hback_porch < 1 ||
mode->hdisplay < 1)
return MODE_H_ILLEGAL;
if (vfront_porch > dc->desc->max_vpw + 1 || vfront_porch < 1 ||
vback_porch > dc->desc->max_vpw || vback_porch < 0 ||
mode->vdisplay < 1)
return MODE_V_ILLEGAL;
return MODE_OK;
}
static void atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer *layer)
{
if (!layer)
return;
if (layer->desc->type == ATMEL_HLCDC_BASE_LAYER ||
layer->desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
layer->desc->type == ATMEL_HLCDC_CURSOR_LAYER)
atmel_hlcdc_plane_irq(atmel_hlcdc_layer_to_plane(layer));
}
static irqreturn_t atmel_hlcdc_dc_irq_handler(int irq, void *data)
{
struct drm_device *dev = data;
struct atmel_hlcdc_dc *dc = dev->dev_private;
unsigned long status;
unsigned int imr, isr;
int i;
regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_IMR, &imr);
regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_ISR, &isr);
status = imr & isr;
if (!status)
return IRQ_NONE;
if (status & ATMEL_HLCDC_SOF)
atmel_hlcdc_crtc_irq(dc->crtc);
for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
if (ATMEL_HLCDC_LAYER_STATUS(i) & status)
atmel_hlcdc_layer_irq(dc->layers[i]);
}
return IRQ_HANDLED;
}
static void atmel_hlcdc_dc_irq_postinstall(struct drm_device *dev)
{
struct atmel_hlcdc_dc *dc = dev->dev_private;
unsigned int cfg = 0;
int i;
/* Enable interrupts on activated layers */
for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
if (dc->layers[i])
cfg |= ATMEL_HLCDC_LAYER_STATUS(i);
}
regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IER, cfg);
}
static void atmel_hlcdc_dc_irq_disable(struct drm_device *dev)
{
struct atmel_hlcdc_dc *dc = dev->dev_private;
unsigned int isr;
regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IDR, 0xffffffff);
regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_ISR, &isr);
}
static int atmel_hlcdc_dc_irq_install(struct drm_device *dev, unsigned int irq)
{
int ret;
atmel_hlcdc_dc_irq_disable(dev);
ret = devm_request_irq(dev->dev, irq, atmel_hlcdc_dc_irq_handler, 0,
dev->driver->name, dev);
if (ret)
return ret;
atmel_hlcdc_dc_irq_postinstall(dev);
return 0;
}
static void atmel_hlcdc_dc_irq_uninstall(struct drm_device *dev)
{
atmel_hlcdc_dc_irq_disable(dev);
}
static const struct drm_mode_config_funcs mode_config_funcs = {
.fb_create = drm_gem_fb_create,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
};
static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev)
{
struct atmel_hlcdc_dc *dc = dev->dev_private;
int ret;
drm_mode_config_init(dev);
ret = atmel_hlcdc_create_outputs(dev);
if (ret) {
dev_err(dev->dev, "failed to create HLCDC outputs: %d\n", ret);
return ret;
}
ret = atmel_hlcdc_create_planes(dev);
if (ret) {
dev_err(dev->dev, "failed to create planes: %d\n", ret);
return ret;
}
ret = atmel_hlcdc_crtc_create(dev);
if (ret) {
dev_err(dev->dev, "failed to create crtc\n");
return ret;
}
dev->mode_config.min_width = dc->desc->min_width;
dev->mode_config.min_height = dc->desc->min_height;
dev->mode_config.max_width = dc->desc->max_width;
dev->mode_config.max_height = dc->desc->max_height;
dev->mode_config.funcs = &mode_config_funcs;
dev->mode_config.async_page_flip = true;
return 0;
}
static int atmel_hlcdc_dc_load(struct drm_device *dev)
{
struct platform_device *pdev = to_platform_device(dev->dev);
const struct of_device_id *match;
struct atmel_hlcdc_dc *dc;
int ret;
match = of_match_node(atmel_hlcdc_of_match, dev->dev->parent->of_node);
if (!match) {
dev_err(&pdev->dev, "invalid compatible string\n");
return -ENODEV;
}
if (!match->data) {
dev_err(&pdev->dev, "invalid hlcdc description\n");
return -EINVAL;
}
dc = devm_kzalloc(dev->dev, sizeof(*dc), GFP_KERNEL);
if (!dc)
return -ENOMEM;
dc->desc = match->data;
dc->hlcdc = dev_get_drvdata(dev->dev->parent);
dev->dev_private = dc;
ret = clk_prepare_enable(dc->hlcdc->periph_clk);
if (ret) {
dev_err(dev->dev, "failed to enable periph_clk\n");
return ret;
}
pm_runtime_enable(dev->dev);
ret = drm_vblank_init(dev, 1);
if (ret < 0) {
dev_err(dev->dev, "failed to initialize vblank\n");
goto err_periph_clk_disable;
}
ret = atmel_hlcdc_dc_modeset_init(dev);
if (ret < 0) {
dev_err(dev->dev, "failed to initialize mode setting\n");
goto err_periph_clk_disable;
}
drm_mode_config_reset(dev);
pm_runtime_get_sync(dev->dev);
ret = atmel_hlcdc_dc_irq_install(dev, dc->hlcdc->irq);
pm_runtime_put_sync(dev->dev);
if (ret < 0) {
dev_err(dev->dev, "failed to install IRQ handler\n");
goto err_periph_clk_disable;
}
platform_set_drvdata(pdev, dev);
drm_kms_helper_poll_init(dev);
return 0;
err_periph_clk_disable:
pm_runtime_disable(dev->dev);
clk_disable_unprepare(dc->hlcdc->periph_clk);
return ret;
}
static void atmel_hlcdc_dc_unload(struct drm_device *dev)
{
struct atmel_hlcdc_dc *dc = dev->dev_private;
drm_kms_helper_poll_fini(dev);
drm_atomic_helper_shutdown(dev);
drm_mode_config_cleanup(dev);
pm_runtime_get_sync(dev->dev);
atmel_hlcdc_dc_irq_uninstall(dev);
pm_runtime_put_sync(dev->dev);
dev->dev_private = NULL;
pm_runtime_disable(dev->dev);
clk_disable_unprepare(dc->hlcdc->periph_clk);
}
drm/gem: rename GEM CMA helpers to GEM DMA helpers Rename "GEM CMA" helpers to "GEM DMA" helpers - considering the hierarchy of APIs (mm/cma -> dma -> gem dma) calling them "GEM DMA" seems to be more applicable. Besides that, commit e57924d4ae80 ("drm/doc: Task to rename CMA helpers") requests to rename the CMA helpers and implies that people seem to be confused about the naming. In order to do this renaming the following script was used: ``` #!/bin/bash DIRS="drivers/gpu include/drm Documentation/gpu" REGEX_SYM_UPPER="[0-9A-Z_\-]" REGEX_SYM_LOWER="[0-9a-z_\-]" REGEX_GREP_UPPER="(${REGEX_SYM_UPPER}*)(GEM)_CMA_(${REGEX_SYM_UPPER}*)" REGEX_GREP_LOWER="(${REGEX_SYM_LOWER}*)(gem)_cma_(${REGEX_SYM_LOWER}*)" REGEX_SED_UPPER="s/${REGEX_GREP_UPPER}/\1\2_DMA_\3/g" REGEX_SED_LOWER="s/${REGEX_GREP_LOWER}/\1\2_dma_\3/g" # Find all upper case 'CMA' symbols and replace them with 'DMA'. for ff in $(grep -REHl "${REGEX_GREP_UPPER}" $DIRS) do sed -i -E "$REGEX_SED_UPPER" $ff done # Find all lower case 'cma' symbols and replace them with 'dma'. for ff in $(grep -REHl "${REGEX_GREP_LOWER}" $DIRS) do sed -i -E "$REGEX_SED_LOWER" $ff done # Replace all occurrences of 'CMA' / 'cma' in comments and # documentation files with 'DMA' / 'dma'. for ff in $(grep -RiHl " cma " $DIRS) do sed -i -E "s/ cma / dma /g" $ff sed -i -E "s/ CMA / DMA /g" $ff done # Rename all 'cma_obj's to 'dma_obj'. for ff in $(grep -RiHl "cma_obj" $DIRS) do sed -i -E "s/cma_obj/dma_obj/g" $ff done ``` Only a few more manual modifications were needed, e.g. reverting the following modifications in some DRM Kconfig files - select CMA if HAVE_DMA_CONTIGUOUS + select DMA if HAVE_DMA_CONTIGUOUS as well as manually picking the occurrences of 'CMA'/'cma' in comments and documentation which relate to "GEM CMA", but not "FB CMA". Also drivers/gpu/drm/Makefile was fixed up manually after renaming drm_gem_cma_helper.c to drm_gem_dma_helper.c. This patch is compile-time tested building a x86_64 kernel with `make allyesconfig && make drivers/gpu/drm`. Acked-by: Sam Ravnborg <sam@ravnborg.org> Acked-by: Thomas Zimmermann <tzimmermann@suse.de> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Danilo Krummrich <dakr@redhat.com> Reviewed-by: Liviu Dudau <liviu.dudau@arm.com> #drivers/gpu/drm/arm Signed-off-by: Sam Ravnborg <sam@ravnborg.org> Link: https://patchwork.freedesktop.org/patch/msgid/20220802000405.949236-4-dakr@redhat.com
2022-08-02 02:04:03 +02:00
DEFINE_DRM_GEM_DMA_FOPS(fops);
drm/<drivers>: Constify struct drm_driver Only the following drivers aren't converted: - amdgpu, because of the driver_feature mangling due to virt support. Subsequent patch will address this. - nouveau, because DRIVER_ATOMIC uapi is still not the default on the platforms where it's supported (i.e. again driver_feature mangling) - vc4, again because of driver_feature mangling - qxl, because the ioctl table is somewhere else and moving that is maybe a bit too much, hence the num_ioctls assignment prevents a const driver structure. - arcpgu, because that is stuck behind a pending tiny-fication series from me. - legacy drivers, because legacy requires non-const drm_driver. Note that for armada I also went ahead and made the ioctl array const. Only cc'ing the driver people who've not been converted (everyone else is way too much). v2: Fix one misplaced const static, should be static const (0day) v3: - Improve commit message (Sam) Acked-by: Sam Ravnborg <sam@ravnborg.org> Cc: kernel test robot <lkp@intel.com> Acked-by: Maxime Ripard <mripard@kernel.org> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Sam Ravnborg <sam@ravnborg.org> Cc: Dave Airlie <airlied@redhat.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: virtualization@lists.linux-foundation.org Cc: Harry Wentland <harry.wentland@amd.com> Cc: Leo Li <sunpeng.li@amd.com> Cc: Alex Deucher <alexander.deucher@amd.com> Cc: Christian König <christian.koenig@amd.com> Cc: Eric Anholt <eric@anholt.net> Cc: Maxime Ripard <mripard@kernel.org> Cc: Ben Skeggs <bskeggs@redhat.com> Cc: nouveau@lists.freedesktop.org Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20201104100425.1922351-5-daniel.vetter@ffwll.ch
2020-11-04 11:04:24 +01:00
static const struct drm_driver atmel_hlcdc_dc_driver = {
drm/prime: Actually remove DRIVER_PRIME everywhere Split out to make the functional changes stick out more. All places where DRIVER_PRIME was used have been removed in previous patches already. v2: amdgpu gained DRIVER_SYNCOBJ_TIMELINE. v3: amdgpu lost DRIVER_SYNCOBJ_TIMELINE. v4: Don't add a space in i915_drv.c (Sam) v5: Add note that previous patches removed all the DRIVER_PRIME users already (Emil). v6: Fixupe ingenic (new driver) while applying. Cc: Sam Ravnborg <sam@ravnborg.org> Reviewed-by: Emil Velikov <emil.velikov@collabora.com> Reviewed-by: Eric Anholt <eric@anholt.net> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Cc: amd-gfx@lists.freedesktop.org Cc: etnaviv@lists.freedesktop.org Cc: freedreno@lists.freedesktop.org Cc: intel-gfx@lists.freedesktop.org Cc: lima@lists.freedesktop.org Cc: linux-amlogic@lists.infradead.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-arm-msm@vger.kernel.org Cc: linux-aspeed@lists.ozlabs.org Cc: linux-renesas-soc@vger.kernel.org Cc: linux-rockchip@lists.infradead.org Cc: linux-samsung-soc@vger.kernel.org Cc: linux-stm32@st-md-mailman.stormreply.com Cc: linux-tegra@vger.kernel.org Cc: nouveau@lists.freedesktop.org Cc: NXP Linux Team <linux-imx@nxp.com> Cc: spice-devel@lists.freedesktop.org Cc: virtualization@lists.linux-foundation.org Cc: VMware Graphics <linux-graphics-maintainer@vmware.com> Cc: xen-devel@lists.xenproject.org Link: https://patchwork.freedesktop.org/patch/msgid/20190617153924.414-1-daniel.vetter@ffwll.ch
2019-06-17 17:39:24 +02:00
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
drm/gem: rename GEM CMA helpers to GEM DMA helpers Rename "GEM CMA" helpers to "GEM DMA" helpers - considering the hierarchy of APIs (mm/cma -> dma -> gem dma) calling them "GEM DMA" seems to be more applicable. Besides that, commit e57924d4ae80 ("drm/doc: Task to rename CMA helpers") requests to rename the CMA helpers and implies that people seem to be confused about the naming. In order to do this renaming the following script was used: ``` #!/bin/bash DIRS="drivers/gpu include/drm Documentation/gpu" REGEX_SYM_UPPER="[0-9A-Z_\-]" REGEX_SYM_LOWER="[0-9a-z_\-]" REGEX_GREP_UPPER="(${REGEX_SYM_UPPER}*)(GEM)_CMA_(${REGEX_SYM_UPPER}*)" REGEX_GREP_LOWER="(${REGEX_SYM_LOWER}*)(gem)_cma_(${REGEX_SYM_LOWER}*)" REGEX_SED_UPPER="s/${REGEX_GREP_UPPER}/\1\2_DMA_\3/g" REGEX_SED_LOWER="s/${REGEX_GREP_LOWER}/\1\2_dma_\3/g" # Find all upper case 'CMA' symbols and replace them with 'DMA'. for ff in $(grep -REHl "${REGEX_GREP_UPPER}" $DIRS) do sed -i -E "$REGEX_SED_UPPER" $ff done # Find all lower case 'cma' symbols and replace them with 'dma'. for ff in $(grep -REHl "${REGEX_GREP_LOWER}" $DIRS) do sed -i -E "$REGEX_SED_LOWER" $ff done # Replace all occurrences of 'CMA' / 'cma' in comments and # documentation files with 'DMA' / 'dma'. for ff in $(grep -RiHl " cma " $DIRS) do sed -i -E "s/ cma / dma /g" $ff sed -i -E "s/ CMA / DMA /g" $ff done # Rename all 'cma_obj's to 'dma_obj'. for ff in $(grep -RiHl "cma_obj" $DIRS) do sed -i -E "s/cma_obj/dma_obj/g" $ff done ``` Only a few more manual modifications were needed, e.g. reverting the following modifications in some DRM Kconfig files - select CMA if HAVE_DMA_CONTIGUOUS + select DMA if HAVE_DMA_CONTIGUOUS as well as manually picking the occurrences of 'CMA'/'cma' in comments and documentation which relate to "GEM CMA", but not "FB CMA". Also drivers/gpu/drm/Makefile was fixed up manually after renaming drm_gem_cma_helper.c to drm_gem_dma_helper.c. This patch is compile-time tested building a x86_64 kernel with `make allyesconfig && make drivers/gpu/drm`. Acked-by: Sam Ravnborg <sam@ravnborg.org> Acked-by: Thomas Zimmermann <tzimmermann@suse.de> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Danilo Krummrich <dakr@redhat.com> Reviewed-by: Liviu Dudau <liviu.dudau@arm.com> #drivers/gpu/drm/arm Signed-off-by: Sam Ravnborg <sam@ravnborg.org> Link: https://patchwork.freedesktop.org/patch/msgid/20220802000405.949236-4-dakr@redhat.com
2022-08-02 02:04:03 +02:00
DRM_GEM_DMA_DRIVER_OPS,
.fops = &fops,
.name = "atmel-hlcdc",
.desc = "Atmel HLCD Controller DRM",
.date = "20141504",
.major = 1,
.minor = 0,
};
static int atmel_hlcdc_dc_drm_probe(struct platform_device *pdev)
{
struct drm_device *ddev;
int ret;
ddev = drm_dev_alloc(&atmel_hlcdc_dc_driver, &pdev->dev);
if (IS_ERR(ddev))
return PTR_ERR(ddev);
ret = atmel_hlcdc_dc_load(ddev);
if (ret)
goto err_put;
ret = drm_dev_register(ddev, 0);
if (ret)
goto err_unload;
drm_fbdev_dma_setup(ddev, 24);
return 0;
err_unload:
atmel_hlcdc_dc_unload(ddev);
err_put:
drm_dev_put(ddev);
return ret;
}
static void atmel_hlcdc_dc_drm_remove(struct platform_device *pdev)
{
struct drm_device *ddev = platform_get_drvdata(pdev);
drm_dev_unregister(ddev);
atmel_hlcdc_dc_unload(ddev);
drm_dev_put(ddev);
}
drm: Call drm_atomic_helper_shutdown() at shutdown time for misc drivers Based on grepping through the source code these drivers appear to be missing a call to drm_atomic_helper_shutdown() at system shutdown time. Among other things, this means that if a panel is in use that it won't be cleanly powered off at system shutdown time. The fact that we should call drm_atomic_helper_shutdown() in the case of OS shutdown/restart comes straight out of the kernel doc "driver instance overview" in drm_drv.c. All of the drivers in this patch were fairly straightforward to fix since they already had a call to drm_atomic_helper_shutdown() at remove/unbind time but were just lacking one at system shutdown. The only hitch is that some of these drivers use the component model to register/unregister their DRM devices. The shutdown callback is part of the original device. The typical solution here, based on how other DRM drivers do this, is to keep track of whether the device is bound based on drvdata. In most cases the drvdata is the drm_device, so we can just make sure it is NULL when the device is not bound. In some drivers, this required minor code changes. To make things simpler, drm_atomic_helper_shutdown() has been modified to consider a NULL drm_device as a noop in the patch ("drm/atomic-helper: drm_atomic_helper_shutdown(NULL) should be a noop"). Suggested-by: Maxime Ripard <mripard@kernel.org> Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> Tested-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> Acked-by: Maxime Ripard <mripard@kernel.org> Tested-by: Jernej Skrabec <jernej.skrabec@gmail.com> Reviewed-by: Jernej Skrabec <jernej.skrabec@gmail.com> Reviewed-by: Sui Jingfeng <suijingfeng@loongson.cn> Tested-by: Sui Jingfeng <suijingfeng@loongson.cn> Signed-off-by: Douglas Anderson <dianders@chromium.org> Link: https://patchwork.freedesktop.org/patch/msgid/20230901163944.RFT.2.I9115e5d094a43e687978b0699cc1fe9f2a3452ea@changeid
2023-09-01 16:39:53 -07:00
static void atmel_hlcdc_dc_drm_shutdown(struct platform_device *pdev)
{
drm_atomic_helper_shutdown(platform_get_drvdata(pdev));
}
static int atmel_hlcdc_dc_drm_suspend(struct device *dev)
{
struct drm_device *drm_dev = dev_get_drvdata(dev);
struct atmel_hlcdc_dc *dc = drm_dev->dev_private;
struct regmap *regmap = dc->hlcdc->regmap;
struct drm_atomic_state *state;
state = drm_atomic_helper_suspend(drm_dev);
if (IS_ERR(state))
return PTR_ERR(state);
dc->suspend.state = state;
regmap_read(regmap, ATMEL_HLCDC_IMR, &dc->suspend.imr);
regmap_write(regmap, ATMEL_HLCDC_IDR, dc->suspend.imr);
clk_disable_unprepare(dc->hlcdc->periph_clk);
return 0;
}
static int atmel_hlcdc_dc_drm_resume(struct device *dev)
{
struct drm_device *drm_dev = dev_get_drvdata(dev);
struct atmel_hlcdc_dc *dc = drm_dev->dev_private;
clk_prepare_enable(dc->hlcdc->periph_clk);
regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IER, dc->suspend.imr);
return drm_atomic_helper_resume(drm_dev, dc->suspend.state);
}
static DEFINE_SIMPLE_DEV_PM_OPS(atmel_hlcdc_dc_drm_pm_ops,
atmel_hlcdc_dc_drm_suspend,
atmel_hlcdc_dc_drm_resume);
static const struct of_device_id atmel_hlcdc_dc_of_match[] = {
{ .compatible = "atmel,hlcdc-display-controller" },
{ },
};
static struct platform_driver atmel_hlcdc_dc_platform_driver = {
.probe = atmel_hlcdc_dc_drm_probe,
.remove_new = atmel_hlcdc_dc_drm_remove,
drm: Call drm_atomic_helper_shutdown() at shutdown time for misc drivers Based on grepping through the source code these drivers appear to be missing a call to drm_atomic_helper_shutdown() at system shutdown time. Among other things, this means that if a panel is in use that it won't be cleanly powered off at system shutdown time. The fact that we should call drm_atomic_helper_shutdown() in the case of OS shutdown/restart comes straight out of the kernel doc "driver instance overview" in drm_drv.c. All of the drivers in this patch were fairly straightforward to fix since they already had a call to drm_atomic_helper_shutdown() at remove/unbind time but were just lacking one at system shutdown. The only hitch is that some of these drivers use the component model to register/unregister their DRM devices. The shutdown callback is part of the original device. The typical solution here, based on how other DRM drivers do this, is to keep track of whether the device is bound based on drvdata. In most cases the drvdata is the drm_device, so we can just make sure it is NULL when the device is not bound. In some drivers, this required minor code changes. To make things simpler, drm_atomic_helper_shutdown() has been modified to consider a NULL drm_device as a noop in the patch ("drm/atomic-helper: drm_atomic_helper_shutdown(NULL) should be a noop"). Suggested-by: Maxime Ripard <mripard@kernel.org> Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> Tested-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> Acked-by: Maxime Ripard <mripard@kernel.org> Tested-by: Jernej Skrabec <jernej.skrabec@gmail.com> Reviewed-by: Jernej Skrabec <jernej.skrabec@gmail.com> Reviewed-by: Sui Jingfeng <suijingfeng@loongson.cn> Tested-by: Sui Jingfeng <suijingfeng@loongson.cn> Signed-off-by: Douglas Anderson <dianders@chromium.org> Link: https://patchwork.freedesktop.org/patch/msgid/20230901163944.RFT.2.I9115e5d094a43e687978b0699cc1fe9f2a3452ea@changeid
2023-09-01 16:39:53 -07:00
.shutdown = atmel_hlcdc_dc_drm_shutdown,
.driver = {
.name = "atmel-hlcdc-display-controller",
.pm = pm_sleep_ptr(&atmel_hlcdc_dc_drm_pm_ops),
.of_match_table = atmel_hlcdc_dc_of_match,
},
};
drm_module_platform_driver(atmel_hlcdc_dc_platform_driver);
MODULE_AUTHOR("Jean-Jacques Hiblot <jjhiblot@traphandler.com>");
MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
MODULE_DESCRIPTION("Atmel HLCDC Display Controller DRM Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:atmel-hlcdc-dc");