cregit-Linux how code gets into the kernel

Release 4.8 drivers/gpu/drm/imx/imx-drm-core.c

/*
 * Freescale i.MX drm driver
 *
 * Copyright (C) 2011 Sascha Hauer, Pengutronix
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */
#include <linux/component.h>
#include <linux/device.h>
#include <linux/dma-buf.h>
#include <linux/fb.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/reservation.h>
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_of.h>
#include <video/imx-ipu-v3.h>

#include "imx-drm.h"


#define MAX_CRTC	4


struct imx_drm_component {
	
struct device_node *of_node;
	
struct list_head list;
};


struct imx_drm_device {
	
struct drm_device			*drm;
	
struct imx_drm_crtc			*crtc[MAX_CRTC];
	
unsigned int				pipes;
	
struct drm_fbdev_cma			*fbhelper;
	
struct drm_atomic_state			*state;
};


struct imx_drm_crtc {
	
struct drm_crtc				*crtc;
	
struct imx_drm_crtc_helper_funcs	imx_drm_helper_funcs;
};

#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)

static int legacyfb_depth = 16;
module_param(legacyfb_depth, int, 0444);
#endif


unsigned int imx_drm_crtc_id(struct imx_drm_crtc *crtc) { return drm_crtc_index(crtc->crtc); }

Contributors

PersonTokensPropCommitsCommitProp
philipp zabelphilipp zabel1473.68%133.33%
thierry redingthierry reding526.32%266.67%
Total19100.00%3100.00%

EXPORT_SYMBOL_GPL(imx_drm_crtc_id);
static void imx_drm_driver_lastclose(struct drm_device *drm) { struct imx_drm_device *imxdrm = drm->dev_private; drm_fbdev_cma_restore_mode(imxdrm->fbhelper); }

Contributors

PersonTokensPropCommitsCommitProp
sascha hauersascha hauer27100.00%1100.00%
Total27100.00%1100.00%


static int imx_drm_driver_unload(struct drm_device *drm) { struct imx_drm_device *imxdrm = drm->dev_private; drm_kms_helper_poll_fini(drm); if (imxdrm->fbhelper) drm_fbdev_cma_fini(imxdrm->fbhelper); component_unbind_all(drm->dev, drm); drm_vblank_cleanup(drm); drm_mode_config_cleanup(drm); platform_set_drvdata(drm->platformdev, NULL); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
russell kingrussell king3347.83%466.67%
sascha hauersascha hauer2739.13%116.67%
shawn guoshawn guo913.04%116.67%
Total69100.00%6100.00%


int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc) { return drm_crtc_vblank_get(imx_drm_crtc->crtc); }

Contributors

PersonTokensPropCommitsCommitProp
sascha hauersascha hauer1688.89%133.33%
russell kingrussell king15.56%133.33%
thierry redingthierry reding15.56%133.33%
Total18100.00%3100.00%

EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_get);
void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc) { drm_crtc_vblank_put(imx_drm_crtc->crtc); }

Contributors

PersonTokensPropCommitsCommitProp
sascha hauersascha hauer1588.24%133.33%
thierry redingthierry reding15.88%133.33%
russell kingrussell king15.88%133.33%
Total17100.00%3100.00%

EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_put);
void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc) { drm_crtc_handle_vblank(imx_drm_crtc->crtc); }

Contributors

PersonTokensPropCommitsCommitProp
sascha hauersascha hauer1588.24%133.33%
russell kingrussell king15.88%133.33%
thierry redingthierry reding15.88%133.33%
Total17100.00%3100.00%

EXPORT_SYMBOL_GPL(imx_drm_handle_vblank);
static int imx_drm_enable_vblank(struct drm_device *drm, unsigned int pipe) { struct imx_drm_device *imxdrm = drm->dev_private; struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[pipe]; int ret; if (!imx_drm_crtc) return -EINVAL; if (!imx_drm_crtc->imx_drm_helper_funcs.enable_vblank) return -ENOSYS; ret = imx_drm_crtc->imx_drm_helper_funcs.enable_vblank( imx_drm_crtc->crtc); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
sascha hauersascha hauer6888.31%133.33%
russell kingrussell king67.79%133.33%
thierry redingthierry reding33.90%133.33%
Total77100.00%3100.00%


static void imx_drm_disable_vblank(struct drm_device *drm, unsigned int pipe) { struct imx_drm_device *imxdrm = drm->dev_private; struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[pipe]; if (!imx_drm_crtc) return; if (!imx_drm_crtc->imx_drm_helper_funcs.disable_vblank) return; imx_drm_crtc->imx_drm_helper_funcs.disable_vblank(imx_drm_crtc->crtc); }

Contributors

PersonTokensPropCommitsCommitProp
sascha hauersascha hauer5587.30%133.33%
russell kingrussell king57.94%133.33%
thierry redingthierry reding34.76%133.33%
Total63100.00%3100.00%

static const struct file_operations imx_drm_driver_fops = { .owner = THIS_MODULE, .open = drm_open, .release = drm_release, .unlocked_ioctl = drm_ioctl, .mmap = drm_gem_cma_mmap, .poll = drm_poll, .read = drm_read, .llseek = noop_llseek, };
void imx_drm_connector_destroy(struct drm_connector *connector) { drm_connector_unregister(connector); drm_connector_cleanup(connector); }

Contributors

PersonTokensPropCommitsCommitProp
sascha hauersascha hauer1155.00%133.33%
russell kingrussell king840.00%133.33%
thomas woodthomas wood15.00%133.33%
Total20100.00%3100.00%

EXPORT_SYMBOL_GPL(imx_drm_connector_destroy);
void imx_drm_encoder_destroy(struct drm_encoder *encoder) { drm_encoder_cleanup(encoder); }

Contributors

PersonTokensPropCommitsCommitProp
russell kingrussell king1280.00%150.00%
sascha hauersascha hauer320.00%150.00%
Total15100.00%2100.00%

EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy);
static void imx_drm_output_poll_changed(struct drm_device *drm) { struct imx_drm_device *imxdrm = drm->dev_private; drm_fbdev_cma_hotplug_event(imxdrm->fbhelper); }

Contributors

PersonTokensPropCommitsCommitProp
russell kingrussell king27100.00%1100.00%
Total27100.00%1100.00%


static int imx_drm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) { int ret; ret = drm_atomic_helper_check_modeset(dev, state); if (ret) return ret; ret = drm_atomic_helper_check_planes(dev, state); if (ret) return ret; /* * Check modeset again in case crtc_state->mode_changed is * updated in plane's ->atomic_check callback. */ ret = drm_atomic_helper_check_modeset(dev, state); if (ret) return ret; return ret; }

Contributors

PersonTokensPropCommitsCommitProp
liu yingliu ying71100.00%1100.00%
Total71100.00%1100.00%

static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = { .fb_create = drm_fb_cma_create, .output_poll_changed = imx_drm_output_poll_changed, .atomic_check = imx_drm_atomic_check, .atomic_commit = drm_atomic_helper_commit, };
static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; struct drm_plane_state *plane_state; struct drm_gem_cma_object *cma_obj; struct fence *excl; unsigned shared_count; struct fence **shared; unsigned int i, j; int ret; /* Wait for fences. */ for_each_crtc_in_state(state, crtc, crtc_state, i) { plane_state = crtc->primary->state; if (plane_state->fb) { cma_obj = drm_fb_cma_get_gem_obj(plane_state->fb, 0); if (cma_obj->base.dma_buf) { ret = reservation_object_get_fences_rcu( cma_obj->base.dma_buf->resv, &excl, &shared_count, &shared); if (unlikely(ret)) DRM_ERROR("failed to get fences " "for buffer\n"); if (excl) { fence_wait(excl, false); fence_put(excl); } for (j = 0; j < shared_count; i++) { fence_wait(shared[j], false); fence_put(shared[j]); } } } } drm_atomic_helper_commit_modeset_disables(dev, state); drm_atomic_helper_commit_planes(dev, state, true); drm_atomic_helper_commit_modeset_enables(dev, state); drm_atomic_helper_commit_hw_done(state); drm_atomic_helper_wait_for_vblanks(dev, state); drm_atomic_helper_cleanup_planes(dev, state); }

Contributors

PersonTokensPropCommitsCommitProp
liu yingliu ying241100.00%1100.00%
Total241100.00%1100.00%

static struct drm_mode_config_helper_funcs imx_drm_mode_config_helpers = { .atomic_commit_tail = imx_drm_atomic_commit_tail, }; /* * Main DRM initialisation. This binds, initialises and registers * with DRM the subcomponents of the driver. */
static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags) { struct imx_drm_device *imxdrm; struct drm_connector *connector; int ret; imxdrm = devm_kzalloc(drm->dev, sizeof(*imxdrm), GFP_KERNEL); if (!imxdrm) return -ENOMEM; imxdrm->drm = drm; drm->dev_private = imxdrm; /* * enable drm irq mode. * - with irq_enabled = true, we can use the vblank feature. * * P.S. note that we wouldn't use drm irq handler but * just specific driver own one instead because * drm framework supports only one irq handler and * drivers can well take care of their interrupts */ drm->irq_enabled = true; /* * set max width and height as default value(4096x4096). * this value would be used to check framebuffer size limitation * at drm_mode_addfb(). */ drm->mode_config.min_width = 64; drm->mode_config.min_height = 64; drm->mode_config.max_width = 4096; drm->mode_config.max_height = 4096; drm->mode_config.funcs = &imx_drm_mode_config_funcs; drm->mode_config.helper_private = &imx_drm_mode_config_helpers; drm_mode_config_init(drm); ret = drm_vblank_init(drm, MAX_CRTC); if (ret) goto err_kms; platform_set_drvdata(drm->platformdev, drm); /* Now try and bind all our sub-components */ ret = component_bind_all(drm->dev, drm); if (ret) goto err_vblank; /* * All components are now added, we can publish the connector sysfs * entries to userspace. This will generate hotplug events and so * userspace will expect to be able to access DRM at this point. */ list_for_each_entry(connector, &drm->mode_config.connector_list, head) { ret = drm_connector_register(connector); if (ret) { dev_err(drm->dev, "[CONNECTOR:%d:%s] drm_connector_register failed: %d\n", connector->base.id, connector->name, ret); goto err_unbind; } } drm_mode_config_reset(drm); /* * All components are now initialised, so setup the fb helper. * The fb helper takes copies of key hardware information, so the * crtcs/connectors/encoders must not change after this point. */ #if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) if (legacyfb_depth != 16 && legacyfb_depth != 32) { dev_warn(drm->dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n"); legacyfb_depth = 16; } imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth, drm->mode_config.num_crtc, MAX_CRTC); if (IS_ERR(imxdrm->fbhelper)) { ret = PTR_ERR(imxdrm->fbhelper); imxdrm->fbhelper = NULL; goto err_unbind; } #endif drm_kms_helper_poll_init(drm); return 0; err_unbind: component_unbind_all(drm->dev, drm); err_vblank: drm_vblank_cleanup(drm); err_kms: drm_mode_config_cleanup(drm); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
russell kingrussell king24470.93%857.14%
sascha hauersascha hauer8123.55%17.14%
liu yingliu ying144.07%214.29%
jani nikulajani nikula20.58%17.14%
thomas woodthomas wood20.58%17.14%
archit tanejaarchit taneja10.29%17.14%
Total344100.00%14100.00%

/* * imx_drm_add_crtc - add a new crtc */
int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, struct imx_drm_crtc **new_crtc, struct drm_plane *primary_plane, const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs, struct device_node *port) { struct imx_drm_device *imxdrm = drm->dev_private; struct imx_drm_crtc *imx_drm_crtc; /* * The vblank arrays are dimensioned by MAX_CRTC - we can't * pass IDs greater than this to those functions. */ if (imxdrm->pipes >= MAX_CRTC) return -EINVAL; if (imxdrm->drm->open_count) return -EBUSY; imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL); if (!imx_drm_crtc) return -ENOMEM; imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs; imx_drm_crtc->crtc = crtc; crtc->port = port; imxdrm->crtc[imxdrm->pipes++] = imx_drm_crtc; *new_crtc = imx_drm_crtc; drm_crtc_helper_add(crtc, imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs); drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL, imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs, NULL); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
russell kingrussell king9053.89%337.50%
sascha hauersascha hauer5935.33%112.50%
philipp zabelphilipp zabel137.78%225.00%
thierry redingthierry reding31.80%112.50%
ville syrjalaville syrjala21.20%112.50%
Total167100.00%8100.00%

EXPORT_SYMBOL_GPL(imx_drm_add_crtc); /* * imx_drm_remove_crtc - remove a crtc */
int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc) { struct imx_drm_device *imxdrm = imx_drm_crtc->crtc->dev->dev_private; unsigned int pipe = drm_crtc_index(imx_drm_crtc->crtc); drm_crtc_cleanup(imx_drm_crtc->crtc); imxdrm->crtc[pipe] = NULL; kfree(imx_drm_crtc); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
sascha hauersascha hauer2543.10%125.00%
russell kingrussell king2237.93%250.00%
thierry redingthierry reding1118.97%125.00%
Total58100.00%4100.00%

EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);
int imx_drm_encoder_parse_of(struct drm_device *drm, struct drm_encoder *encoder, struct device_node *np) { uint32_t crtc_mask = drm_of_find_possible_crtcs(drm, np); /* * If we failed to find the CRTC(s) which this encoder is * supposed to be connected to, it's because the CRTC has * not been registered yet. Defer probing, and hope that * the required CRTC is added later. */ if (crtc_mask == 0) return -EPROBE_DEFER; encoder->possible_crtcs = crtc_mask; /* FIXME: this is the mask of outputs which can clone this output. */ encoder->possible_clones = ~0; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
russell kingrussell king4272.41%250.00%
philipp zabelphilipp zabel1220.69%125.00%
sascha hauersascha hauer46.90%125.00%
Total58100.00%4100.00%

EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of); static const struct drm_ioctl_desc imx_drm_ioctls[] = { /* none so far */ }; static struct drm_driver imx_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC, .load = imx_drm_driver_load, .unload = imx_drm_driver_unload, .lastclose = imx_drm_driver_lastclose, .gem_free_object_unlocked = drm_gem_cma_free_object, .gem_vm_ops = &drm_gem_cma_vm_ops, .dumb_create = drm_gem_cma_dumb_create, .dumb_map_offset = drm_gem_cma_dumb_map_offset, .dumb_destroy = drm_gem_dumb_destroy, .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_import = drm_gem_prime_import, .gem_prime_export = drm_gem_prime_export, .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, .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = imx_drm_enable_vblank, .disable_vblank = imx_drm_disable_vblank, .ioctls = imx_drm_ioctls, .num_ioctls = ARRAY_SIZE(imx_drm_ioctls), .fops = &imx_drm_driver_fops, .name = "imx-drm", .desc = "i.MX DRM graphics", .date = "20120507", .major = 1, .minor = 0, .patchlevel = 0, };
static int compare_of(struct device *dev, void *data) { struct device_node *np = data; /* Special case for DI, dev->of_node may not be set yet */ if (strcmp(dev->driver->name, "imx-ipuv3-crtc") == 0) { struct ipu_client_platformdata *pdata = dev->platform_data; return pdata->of_node == np; } /* Special case for LDB, one device for two channels */ if (of_node_cmp(np->name, "lvds-channel") == 0) { np = of_get_parent(np); of_node_put(np); } return dev->of_node == np; }

Contributors

PersonTokensPropCommitsCommitProp
philipp zabelphilipp zabel6268.13%266.67%
russell kingrussell king2931.87%133.33%
Total91100.00%3100.00%


static int imx_drm_bind(struct device *dev) { return drm_platform_init(&imx_drm_driver, to_platform_device(dev)); }

Contributors

PersonTokensPropCommitsCommitProp
russell kingrussell king23100.00%1100.00%
Total23100.00%1100.00%


static void imx_drm_unbind(struct device *dev) { drm_put_dev(dev_get_drvdata(dev)); }

Contributors

PersonTokensPropCommitsCommitProp
russell kingrussell king19100.00%1100.00%
Total19100.00%1100.00%

static const struct component_master_ops imx_drm_ops = { .bind = imx_drm_bind, .unbind = imx_drm_unbind, };
static int imx_drm_platform_probe(struct platform_device *pdev) { int ret = drm_of_component_probe(&pdev->dev, compare_of, &imx_drm_ops); if (!ret) ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
russell kingrussell king2244.00%233.33%
sascha hauersascha hauer1122.00%116.67%
philipp zabelphilipp zabel816.00%116.67%
liviu dudauliviu dudau510.00%116.67%
shawn guoshawn guo48.00%116.67%
Total50100.00%6100.00%


static int imx_drm_platform_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &imx_drm_ops); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
sascha hauersascha hauer1768.00%133.33%
russell kingrussell king728.00%133.33%
daniel vetterdaniel vetter14.00%133.33%
Total25100.00%3100.00%

#ifdef CONFIG_PM_SLEEP
static int imx_drm_suspend(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); struct imx_drm_device *imxdrm; /* The drm_dev is NULL before .load hook is called */ if (drm_dev == NULL) return 0; drm_kms_helper_poll_disable(drm_dev); imxdrm = drm_dev->dev_private; imxdrm->state = drm_atomic_helper_suspend(drm_dev); if (IS_ERR(imxdrm->state)) { drm_kms_helper_poll_enable(drm_dev); return PTR_ERR(imxdrm->state); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
liu yingliu ying4453.01%150.00%
shawn guoshawn guo3946.99%150.00%
Total83100.00%2100.00%


static int imx_drm_resume(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); struct imx_drm_device *imx_drm; if (drm_dev == NULL) return 0; imx_drm = drm_dev->dev_private; drm_atomic_helper_resume(drm_dev, imx_drm->state); drm_kms_helper_poll_enable(drm_dev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
shawn guoshawn guo4272.41%150.00%
liu yingliu ying1627.59%150.00%
Total58100.00%2100.00%

#endif static SIMPLE_DEV_PM_OPS(imx_drm_pm_ops, imx_drm_suspend, imx_drm_resume); static const struct of_device_id imx_drm_dt_ids[] = { { .compatible = "fsl,imx-display-subsystem", }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, imx_drm_dt_ids); static struct platform_driver imx_drm_pdrv = { .probe = imx_drm_platform_probe, .remove = imx_drm_platform_remove, .driver = { .name = "imx-drm", .pm = &imx_drm_pm_ops, .of_match_table = imx_drm_dt_ids, }, }; module_platform_driver(imx_drm_pdrv); MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); MODULE_DESCRIPTION("i.MX drm driver core"); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
sascha hauersascha hauer72532.48%12.27%
russell kingrussell king70631.63%1636.36%
liu yingliu ying42719.13%49.09%
philipp zabelphilipp zabel1928.60%511.36%
shawn guoshawn guo1155.15%24.55%
thierry redingthierry reding291.30%36.82%
archit tanejaarchit taneja90.40%12.27%
daniel vetterdaniel vetter60.27%49.09%
josh boyerjosh boyer50.22%12.27%
liviu dudauliviu dudau50.22%12.27%
ville syrjalaville syrjala40.18%36.82%
fabio estevamfabio estevam40.18%12.27%
thomas woodthomas wood30.13%12.27%
jani nikulajani nikula20.09%12.27%
Total2232100.00%44100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.