Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
0004  * Parts of this file were based on sources as follows:
0005  *
0006  * Copyright (C) 2006-2008 Intel Corporation
0007  * Copyright (C) 2007 Amos Lee <amos_lee@storlinksemi.com>
0008  * Copyright (C) 2007 Dave Airlie <airlied@linux.ie>
0009  * Copyright (C) 2011 Texas Instruments
0010  * Copyright (C) 2017 Eric Anholt
0011  */
0012 
0013 /**
0014  * DOC: Faraday TV Encoder TVE200 DRM Driver
0015  *
0016  * The Faraday TV Encoder TVE200 is also known as the Gemini TV Interface
0017  * Controller (TVC) and is found in the Gemini Chipset from Storlink
0018  * Semiconductor (later Storm Semiconductor, later Cortina Systems)
0019  * but also in the Grain Media GM8180 chipset. On the Gemini the module
0020  * is connected to 8 data lines and a single clock line, comprising an
0021  * 8-bit BT.656 interface.
0022  *
0023  * This is a very basic YUV display driver. The datasheet specifies that
0024  * it supports the ITU BT.656 standard. It requires a 27 MHz clock which is
0025  * the hallmark of any TV encoder supporting both PAL and NTSC.
0026  *
0027  * This driver exposes a standard KMS interface for this TV encoder.
0028  */
0029 
0030 #include <linux/clk.h>
0031 #include <linux/dma-buf.h>
0032 #include <linux/irq.h>
0033 #include <linux/io.h>
0034 #include <linux/module.h>
0035 #include <linux/platform_device.h>
0036 #include <linux/shmem_fs.h>
0037 #include <linux/slab.h>
0038 
0039 #include <drm/drm_atomic_helper.h>
0040 #include <drm/drm_bridge.h>
0041 #include <drm/drm_drv.h>
0042 #include <drm/drm_fb_cma_helper.h>
0043 #include <drm/drm_fb_helper.h>
0044 #include <drm/drm_gem_cma_helper.h>
0045 #include <drm/drm_gem_framebuffer_helper.h>
0046 #include <drm/drm_module.h>
0047 #include <drm/drm_of.h>
0048 #include <drm/drm_panel.h>
0049 #include <drm/drm_probe_helper.h>
0050 #include <drm/drm_vblank.h>
0051 
0052 #include "tve200_drm.h"
0053 
0054 #define DRIVER_DESC      "DRM module for Faraday TVE200"
0055 
0056 static const struct drm_mode_config_funcs mode_config_funcs = {
0057     .fb_create = drm_gem_fb_create,
0058     .atomic_check = drm_atomic_helper_check,
0059     .atomic_commit = drm_atomic_helper_commit,
0060 };
0061 
0062 static int tve200_modeset_init(struct drm_device *dev)
0063 {
0064     struct drm_mode_config *mode_config;
0065     struct tve200_drm_dev_private *priv = dev->dev_private;
0066     struct drm_panel *panel;
0067     struct drm_bridge *bridge;
0068     int ret = 0;
0069 
0070     drm_mode_config_init(dev);
0071     mode_config = &dev->mode_config;
0072     mode_config->funcs = &mode_config_funcs;
0073     mode_config->min_width = 352;
0074     mode_config->max_width = 720;
0075     mode_config->min_height = 240;
0076     mode_config->max_height = 576;
0077 
0078     ret = drm_of_find_panel_or_bridge(dev->dev->of_node,
0079                       0, 0, &panel, &bridge);
0080     if (ret && ret != -ENODEV)
0081         return ret;
0082     if (panel) {
0083         bridge = drm_panel_bridge_add_typed(panel,
0084                             DRM_MODE_CONNECTOR_Unknown);
0085         if (IS_ERR(bridge)) {
0086             ret = PTR_ERR(bridge);
0087             goto out_bridge;
0088         }
0089     } else {
0090         /*
0091          * TODO: when we are using a different bridge than a panel
0092          * (such as a dumb VGA connector) we need to devise a different
0093          * method to get the connector out of the bridge.
0094          */
0095         dev_err(dev->dev, "the bridge is not a panel\n");
0096         goto out_bridge;
0097     }
0098 
0099     ret = tve200_display_init(dev);
0100     if (ret) {
0101         dev_err(dev->dev, "failed to init display\n");
0102         goto out_bridge;
0103     }
0104 
0105     ret = drm_simple_display_pipe_attach_bridge(&priv->pipe,
0106                             bridge);
0107     if (ret) {
0108         dev_err(dev->dev, "failed to attach bridge\n");
0109         goto out_bridge;
0110     }
0111 
0112     priv->panel = panel;
0113     priv->connector = drm_panel_bridge_connector(bridge);
0114     priv->bridge = bridge;
0115 
0116     dev_info(dev->dev, "attached to panel %s\n",
0117          dev_name(panel->dev));
0118 
0119     ret = drm_vblank_init(dev, 1);
0120     if (ret) {
0121         dev_err(dev->dev, "failed to init vblank\n");
0122         goto out_bridge;
0123     }
0124 
0125     drm_mode_config_reset(dev);
0126     drm_kms_helper_poll_init(dev);
0127 
0128     goto finish;
0129 
0130 out_bridge:
0131     if (panel)
0132         drm_panel_bridge_remove(bridge);
0133     drm_mode_config_cleanup(dev);
0134 finish:
0135     return ret;
0136 }
0137 
0138 DEFINE_DRM_GEM_CMA_FOPS(drm_fops);
0139 
0140 static const struct drm_driver tve200_drm_driver = {
0141     .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
0142     .ioctls = NULL,
0143     .fops = &drm_fops,
0144     .name = "tve200",
0145     .desc = DRIVER_DESC,
0146     .date = "20170703",
0147     .major = 1,
0148     .minor = 0,
0149     .patchlevel = 0,
0150     DRM_GEM_CMA_DRIVER_OPS,
0151 };
0152 
0153 static int tve200_probe(struct platform_device *pdev)
0154 {
0155     struct device *dev = &pdev->dev;
0156     struct tve200_drm_dev_private *priv;
0157     struct drm_device *drm;
0158     struct resource *res;
0159     int irq;
0160     int ret;
0161 
0162     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0163     if (!priv)
0164         return -ENOMEM;
0165 
0166     drm = drm_dev_alloc(&tve200_drm_driver, dev);
0167     if (IS_ERR(drm))
0168         return PTR_ERR(drm);
0169     platform_set_drvdata(pdev, drm);
0170     priv->drm = drm;
0171     drm->dev_private = priv;
0172 
0173     /* Clock the silicon so we can access the registers */
0174     priv->pclk = devm_clk_get(dev, "PCLK");
0175     if (IS_ERR(priv->pclk)) {
0176         dev_err(dev, "unable to get PCLK\n");
0177         ret = PTR_ERR(priv->pclk);
0178         goto dev_unref;
0179     }
0180     ret = clk_prepare_enable(priv->pclk);
0181     if (ret) {
0182         dev_err(dev, "failed to enable PCLK\n");
0183         goto dev_unref;
0184     }
0185 
0186     /* This clock is for the pixels (27MHz) */
0187     priv->clk = devm_clk_get(dev, "TVE");
0188     if (IS_ERR(priv->clk)) {
0189         dev_err(dev, "unable to get TVE clock\n");
0190         ret = PTR_ERR(priv->clk);
0191         goto clk_disable;
0192     }
0193 
0194     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0195     priv->regs = devm_ioremap_resource(dev, res);
0196     if (IS_ERR(priv->regs)) {
0197         dev_err(dev, "%s failed mmio\n", __func__);
0198         ret = -EINVAL;
0199         goto clk_disable;
0200     }
0201 
0202     irq = platform_get_irq(pdev, 0);
0203     if (irq < 0) {
0204         ret = irq;
0205         goto clk_disable;
0206     }
0207 
0208     /* turn off interrupts before requesting the irq */
0209     writel(0, priv->regs + TVE200_INT_EN);
0210 
0211     ret = devm_request_irq(dev, irq, tve200_irq, 0, "tve200", priv);
0212     if (ret) {
0213         dev_err(dev, "failed to request irq %d\n", ret);
0214         goto clk_disable;
0215     }
0216 
0217     ret = tve200_modeset_init(drm);
0218     if (ret)
0219         goto clk_disable;
0220 
0221     ret = drm_dev_register(drm, 0);
0222     if (ret < 0)
0223         goto clk_disable;
0224 
0225     /*
0226      * Passing in 16 here will make the RGB565 mode the default
0227      * Passing in 32 will use XRGB8888 mode
0228      */
0229     drm_fbdev_generic_setup(drm, 16);
0230 
0231     return 0;
0232 
0233 clk_disable:
0234     clk_disable_unprepare(priv->pclk);
0235 dev_unref:
0236     drm_dev_put(drm);
0237     return ret;
0238 }
0239 
0240 static int tve200_remove(struct platform_device *pdev)
0241 {
0242     struct drm_device *drm = platform_get_drvdata(pdev);
0243     struct tve200_drm_dev_private *priv = drm->dev_private;
0244 
0245     drm_dev_unregister(drm);
0246     if (priv->panel)
0247         drm_panel_bridge_remove(priv->bridge);
0248     drm_mode_config_cleanup(drm);
0249     clk_disable_unprepare(priv->pclk);
0250     drm_dev_put(drm);
0251 
0252     return 0;
0253 }
0254 
0255 static const struct of_device_id tve200_of_match[] = {
0256     {
0257         .compatible = "faraday,tve200",
0258     },
0259     {},
0260 };
0261 
0262 static struct platform_driver tve200_driver = {
0263     .driver = {
0264         .name           = "tve200",
0265         .of_match_table = of_match_ptr(tve200_of_match),
0266     },
0267     .probe = tve200_probe,
0268     .remove = tve200_remove,
0269 };
0270 drm_module_platform_driver(tve200_driver);
0271 
0272 MODULE_DESCRIPTION(DRIVER_DESC);
0273 MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
0274 MODULE_LICENSE("GPL");