Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Linus Walleij | 978 | 96.17% | 3 | 21.43% |
Noralf Trönnes | 13 | 1.28% | 3 | 21.43% |
Sam Ravnborg | 10 | 0.98% | 2 | 14.29% |
Daniel Vetter | 7 | 0.69% | 1 | 7.14% |
Dan Carpenter | 3 | 0.29% | 1 | 7.14% |
Thomas Gleixner | 2 | 0.20% | 1 | 7.14% |
Fernando Ramos | 2 | 0.20% | 1 | 7.14% |
Laurent Pinchart | 1 | 0.10% | 1 | 7.14% |
Thomas Zimmermann | 1 | 0.10% | 1 | 7.14% |
Total | 1017 | 14 |
// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> * Parts of this file were based on sources as follows: * * Copyright (C) 2006-2008 Intel Corporation * Copyright (C) 2007 Amos Lee <amos_lee@storlinksemi.com> * Copyright (C) 2007 Dave Airlie <airlied@linux.ie> * Copyright (C) 2011 Texas Instruments * Copyright (C) 2017 Eric Anholt */ /** * DOC: Faraday TV Encoder TVE200 DRM Driver * * The Faraday TV Encoder TVE200 is also known as the Gemini TV Interface * Controller (TVC) and is found in the Gemini Chipset from Storlink * Semiconductor (later Storm Semiconductor, later Cortina Systems) * but also in the Grain Media GM8180 chipset. On the Gemini the module * is connected to 8 data lines and a single clock line, comprising an * 8-bit BT.656 interface. * * This is a very basic YUV display driver. The datasheet specifies that * it supports the ITU BT.656 standard. It requires a 27 MHz clock which is * the hallmark of any TV encoder supporting both PAL and NTSC. * * This driver exposes a standard KMS interface for this TV encoder. */ #include <linux/clk.h> #include <linux/dma-buf.h> #include <linux/irq.h> #include <linux/io.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/shmem_fs.h> #include <linux/slab.h> #include <linux/version.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_drv.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_of.h> #include <drm/drm_panel.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> #include "tve200_drm.h" #define DRIVER_DESC "DRM module for Faraday TVE200" 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 tve200_modeset_init(struct drm_device *dev) { struct drm_mode_config *mode_config; struct tve200_drm_dev_private *priv = dev->dev_private; struct drm_panel *panel; struct drm_bridge *bridge; int ret = 0; drm_mode_config_init(dev); mode_config = &dev->mode_config; mode_config->funcs = &mode_config_funcs; mode_config->min_width = 352; mode_config->max_width = 720; mode_config->min_height = 240; mode_config->max_height = 576; ret = drm_of_find_panel_or_bridge(dev->dev->of_node, 0, 0, &panel, &bridge); if (ret && ret != -ENODEV) return ret; if (panel) { bridge = drm_panel_bridge_add_typed(panel, DRM_MODE_CONNECTOR_Unknown); if (IS_ERR(bridge)) { ret = PTR_ERR(bridge); goto out_bridge; } } else { /* * TODO: when we are using a different bridge than a panel * (such as a dumb VGA connector) we need to devise a different * method to get the connector out of the bridge. */ dev_err(dev->dev, "the bridge is not a panel\n"); goto out_bridge; } ret = tve200_display_init(dev); if (ret) { dev_err(dev->dev, "failed to init display\n"); goto out_bridge; } ret = drm_simple_display_pipe_attach_bridge(&priv->pipe, bridge); if (ret) { dev_err(dev->dev, "failed to attach bridge\n"); goto out_bridge; } priv->panel = panel; priv->connector = drm_panel_bridge_connector(bridge); priv->bridge = bridge; dev_info(dev->dev, "attached to panel %s\n", dev_name(panel->dev)); ret = drm_vblank_init(dev, 1); if (ret) { dev_err(dev->dev, "failed to init vblank\n"); goto out_bridge; } drm_mode_config_reset(dev); drm_kms_helper_poll_init(dev); goto finish; out_bridge: if (panel) drm_panel_bridge_remove(bridge); drm_mode_config_cleanup(dev); finish: return ret; } DEFINE_DRM_GEM_CMA_FOPS(drm_fops); static struct drm_driver tve200_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, .ioctls = NULL, .fops = &drm_fops, .name = "tve200", .desc = DRIVER_DESC, .date = "20170703", .major = 1, .minor = 0, .patchlevel = 0, DRM_GEM_CMA_DRIVER_OPS, }; static int tve200_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct tve200_drm_dev_private *priv; struct drm_device *drm; struct resource *res; int irq; int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; drm = drm_dev_alloc(&tve200_drm_driver, dev); if (IS_ERR(drm)) return PTR_ERR(drm); platform_set_drvdata(pdev, drm); priv->drm = drm; drm->dev_private = priv; /* Clock the silicon so we can access the registers */ priv->pclk = devm_clk_get(dev, "PCLK"); if (IS_ERR(priv->pclk)) { dev_err(dev, "unable to get PCLK\n"); ret = PTR_ERR(priv->pclk); goto dev_unref; } ret = clk_prepare_enable(priv->pclk); if (ret) { dev_err(dev, "failed to enable PCLK\n"); goto dev_unref; } /* This clock is for the pixels (27MHz) */ priv->clk = devm_clk_get(dev, "TVE"); if (IS_ERR(priv->clk)) { dev_err(dev, "unable to get TVE clock\n"); ret = PTR_ERR(priv->clk); goto clk_disable; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->regs = devm_ioremap_resource(dev, res); if (IS_ERR(priv->regs)) { dev_err(dev, "%s failed mmio\n", __func__); ret = -EINVAL; goto clk_disable; } irq = platform_get_irq(pdev, 0); if (!irq) { ret = -EINVAL; goto clk_disable; } /* turn off interrupts before requesting the irq */ writel(0, priv->regs + TVE200_INT_EN); ret = devm_request_irq(dev, irq, tve200_irq, 0, "tve200", priv); if (ret) { dev_err(dev, "failed to request irq %d\n", ret); goto clk_disable; } ret = tve200_modeset_init(drm); if (ret) goto clk_disable; ret = drm_dev_register(drm, 0); if (ret < 0) goto clk_disable; /* * Passing in 16 here will make the RGB565 mode the default * Passing in 32 will use XRGB8888 mode */ drm_fbdev_generic_setup(drm, 16); return 0; clk_disable: clk_disable_unprepare(priv->pclk); dev_unref: drm_dev_put(drm); return ret; } static int tve200_remove(struct platform_device *pdev) { struct drm_device *drm = platform_get_drvdata(pdev); struct tve200_drm_dev_private *priv = drm->dev_private; drm_dev_unregister(drm); if (priv->panel) drm_panel_bridge_remove(priv->bridge); drm_mode_config_cleanup(drm); clk_disable_unprepare(priv->pclk); drm_dev_put(drm); return 0; } static const struct of_device_id tve200_of_match[] = { { .compatible = "faraday,tve200", }, {}, }; static struct platform_driver tve200_driver = { .driver = { .name = "tve200", .of_match_table = of_match_ptr(tve200_of_match), }, .probe = tve200_probe, .remove = tve200_remove, }; module_platform_driver(tve200_driver); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); MODULE_LICENSE("GPL");
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1