Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Copyright (C) 2019-2022 Bootlin
0004  * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
0005  */
0006 
0007 #include <linux/bitfield.h>
0008 #include <linux/clk.h>
0009 #include <linux/mfd/syscon.h>
0010 #include <linux/module.h>
0011 #include <linux/of.h>
0012 #include <linux/of_address.h>
0013 #include <linux/of_device.h>
0014 #include <linux/of_reserved_mem.h>
0015 #include <linux/regmap.h>
0016 #include <linux/types.h>
0017 
0018 #include <drm/drm_atomic_helper.h>
0019 #include <drm/drm_drv.h>
0020 #include <drm/drm_fb_helper.h>
0021 #include <drm/drm_gem_cma_helper.h>
0022 #include <drm/drm_print.h>
0023 
0024 #include "logicvc_crtc.h"
0025 #include "logicvc_drm.h"
0026 #include "logicvc_interface.h"
0027 #include "logicvc_mode.h"
0028 #include "logicvc_layer.h"
0029 #include "logicvc_of.h"
0030 #include "logicvc_regs.h"
0031 
0032 DEFINE_DRM_GEM_CMA_FOPS(logicvc_drm_fops);
0033 
0034 static int logicvc_drm_gem_cma_dumb_create(struct drm_file *file_priv,
0035                        struct drm_device *drm_dev,
0036                        struct drm_mode_create_dumb *args)
0037 {
0038     struct logicvc_drm *logicvc = logicvc_drm(drm_dev);
0039 
0040     /* Stride is always fixed to its configuration value. */
0041     args->pitch = logicvc->config.row_stride * DIV_ROUND_UP(args->bpp, 8);
0042 
0043     return drm_gem_cma_dumb_create_internal(file_priv, drm_dev, args);
0044 }
0045 
0046 static struct drm_driver logicvc_drm_driver = {
0047     .driver_features        = DRIVER_GEM | DRIVER_MODESET |
0048                       DRIVER_ATOMIC,
0049 
0050     .fops               = &logicvc_drm_fops,
0051     .name               = "logicvc-drm",
0052     .desc               = "Xylon LogiCVC DRM driver",
0053     .date               = "20200403",
0054     .major              = 1,
0055     .minor              = 0,
0056 
0057     DRM_GEM_CMA_DRIVER_OPS_VMAP_WITH_DUMB_CREATE(logicvc_drm_gem_cma_dumb_create),
0058 };
0059 
0060 static struct regmap_config logicvc_drm_regmap_config = {
0061     .reg_bits   = 32,
0062     .val_bits   = 32,
0063     .reg_stride = 4,
0064     .name       = "logicvc-drm",
0065 };
0066 
0067 static irqreturn_t logicvc_drm_irq_handler(int irq, void *data)
0068 {
0069     struct logicvc_drm *logicvc = data;
0070     irqreturn_t ret = IRQ_NONE;
0071     u32 stat = 0;
0072 
0073     /* Get pending interrupt sources. */
0074     regmap_read(logicvc->regmap, LOGICVC_INT_STAT_REG, &stat);
0075 
0076     /* Clear all pending interrupt sources. */
0077     regmap_write(logicvc->regmap, LOGICVC_INT_STAT_REG, stat);
0078 
0079     if (stat & LOGICVC_INT_STAT_V_SYNC) {
0080         logicvc_crtc_vblank_handler(logicvc);
0081         ret = IRQ_HANDLED;
0082     }
0083 
0084     return ret;
0085 }
0086 
0087 static int logicvc_drm_config_parse(struct logicvc_drm *logicvc)
0088 {
0089     struct drm_device *drm_dev = &logicvc->drm_dev;
0090     struct device *dev = drm_dev->dev;
0091     struct device_node *of_node = dev->of_node;
0092     struct logicvc_drm_config *config = &logicvc->config;
0093     struct device_node *layers_node;
0094     int ret;
0095 
0096     logicvc_of_property_parse_bool(of_node, LOGICVC_OF_PROPERTY_DITHERING,
0097                        &config->dithering);
0098     logicvc_of_property_parse_bool(of_node,
0099                        LOGICVC_OF_PROPERTY_BACKGROUND_LAYER,
0100                        &config->background_layer);
0101     logicvc_of_property_parse_bool(of_node,
0102                        LOGICVC_OF_PROPERTY_LAYERS_CONFIGURABLE,
0103                        &config->layers_configurable);
0104 
0105     ret = logicvc_of_property_parse_u32(of_node,
0106                         LOGICVC_OF_PROPERTY_DISPLAY_INTERFACE,
0107                         &config->display_interface);
0108     if (ret)
0109         return ret;
0110 
0111     ret = logicvc_of_property_parse_u32(of_node,
0112                         LOGICVC_OF_PROPERTY_DISPLAY_COLORSPACE,
0113                         &config->display_colorspace);
0114     if (ret)
0115         return ret;
0116 
0117     ret = logicvc_of_property_parse_u32(of_node,
0118                         LOGICVC_OF_PROPERTY_DISPLAY_DEPTH,
0119                         &config->display_depth);
0120     if (ret)
0121         return ret;
0122 
0123     ret = logicvc_of_property_parse_u32(of_node,
0124                         LOGICVC_OF_PROPERTY_ROW_STRIDE,
0125                         &config->row_stride);
0126     if (ret)
0127         return ret;
0128 
0129     layers_node = of_get_child_by_name(of_node, "layers");
0130     if (!layers_node) {
0131         drm_err(drm_dev, "Missing non-optional layers node\n");
0132         return -EINVAL;
0133     }
0134 
0135     config->layers_count = of_get_child_count(layers_node);
0136     if (!config->layers_count) {
0137         drm_err(drm_dev,
0138             "Missing a non-optional layers children node\n");
0139         return -EINVAL;
0140     }
0141 
0142     return 0;
0143 }
0144 
0145 static int logicvc_clocks_prepare(struct logicvc_drm *logicvc)
0146 {
0147     struct drm_device *drm_dev = &logicvc->drm_dev;
0148     struct device *dev = drm_dev->dev;
0149 
0150     struct {
0151         struct clk **clk;
0152         char *name;
0153         bool optional;
0154     } clocks_map[] = {
0155         {
0156             .clk = &logicvc->vclk,
0157             .name = "vclk",
0158             .optional = false,
0159         },
0160         {
0161             .clk = &logicvc->vclk2,
0162             .name = "vclk2",
0163             .optional = true,
0164         },
0165         {
0166             .clk = &logicvc->lvdsclk,
0167             .name = "lvdsclk",
0168             .optional = true,
0169         },
0170         {
0171             .clk = &logicvc->lvdsclkn,
0172             .name = "lvdsclkn",
0173             .optional = true,
0174         },
0175     };
0176     unsigned int i;
0177     int ret;
0178 
0179     for (i = 0; i < ARRAY_SIZE(clocks_map); i++) {
0180         struct clk *clk;
0181 
0182         clk = devm_clk_get(dev, clocks_map[i].name);
0183         if (IS_ERR(clk)) {
0184             if (PTR_ERR(clk) == -ENOENT && clocks_map[i].optional)
0185                 continue;
0186 
0187             drm_err(drm_dev, "Missing non-optional clock %s\n",
0188                 clocks_map[i].name);
0189 
0190             ret = PTR_ERR(clk);
0191             goto error;
0192         }
0193 
0194         ret = clk_prepare_enable(clk);
0195         if (ret) {
0196             drm_err(drm_dev,
0197                 "Failed to prepare and enable clock %s\n",
0198                 clocks_map[i].name);
0199             goto error;
0200         }
0201 
0202         *clocks_map[i].clk = clk;
0203     }
0204 
0205     return 0;
0206 
0207 error:
0208     for (i = 0; i < ARRAY_SIZE(clocks_map); i++) {
0209         if (!*clocks_map[i].clk)
0210             continue;
0211 
0212         clk_disable_unprepare(*clocks_map[i].clk);
0213         *clocks_map[i].clk = NULL;
0214     }
0215 
0216     return ret;
0217 }
0218 
0219 static int logicvc_clocks_unprepare(struct logicvc_drm *logicvc)
0220 {
0221     struct clk **clocks[] = {
0222         &logicvc->vclk,
0223         &logicvc->vclk2,
0224         &logicvc->lvdsclk,
0225         &logicvc->lvdsclkn,
0226     };
0227     unsigned int i;
0228 
0229     for (i = 0; i < ARRAY_SIZE(clocks); i++) {
0230         if (!*clocks[i])
0231             continue;
0232 
0233         clk_disable_unprepare(*clocks[i]);
0234         *clocks[i] = NULL;
0235     }
0236 
0237     return 0;
0238 }
0239 
0240 static const struct logicvc_drm_caps logicvc_drm_caps[] = {
0241     {
0242         .major      = 3,
0243         .layer_address  = false,
0244     },
0245     {
0246         .major      = 4,
0247         .layer_address  = true,
0248     },
0249     {
0250         .major      = 5,
0251         .layer_address  = true,
0252     },
0253 };
0254 
0255 static const struct logicvc_drm_caps *
0256 logicvc_drm_caps_match(struct logicvc_drm *logicvc)
0257 {
0258     struct drm_device *drm_dev = &logicvc->drm_dev;
0259     const struct logicvc_drm_caps *caps = NULL;
0260     unsigned int major, minor;
0261     char level;
0262     unsigned int i;
0263     u32 version;
0264 
0265     regmap_read(logicvc->regmap, LOGICVC_IP_VERSION_REG, &version);
0266 
0267     major = FIELD_GET(LOGICVC_IP_VERSION_MAJOR_MASK, version);
0268     minor = FIELD_GET(LOGICVC_IP_VERSION_MINOR_MASK, version);
0269     level = FIELD_GET(LOGICVC_IP_VERSION_LEVEL_MASK, version) + 'a';
0270 
0271     for (i = 0; i < ARRAY_SIZE(logicvc_drm_caps); i++) {
0272         if (logicvc_drm_caps[i].major &&
0273             logicvc_drm_caps[i].major != major)
0274             continue;
0275 
0276         if (logicvc_drm_caps[i].minor &&
0277             logicvc_drm_caps[i].minor != minor)
0278             continue;
0279 
0280         if (logicvc_drm_caps[i].level &&
0281             logicvc_drm_caps[i].level != level)
0282             continue;
0283 
0284         caps = &logicvc_drm_caps[i];
0285     }
0286 
0287     drm_info(drm_dev, "LogiCVC version %d.%02d.%c\n", major, minor, level);
0288 
0289     return caps;
0290 }
0291 
0292 static int logicvc_drm_probe(struct platform_device *pdev)
0293 {
0294     struct device_node *of_node = pdev->dev.of_node;
0295     struct device_node *reserved_mem_node;
0296     struct reserved_mem *reserved_mem = NULL;
0297     const struct logicvc_drm_caps *caps;
0298     struct logicvc_drm *logicvc;
0299     struct device *dev = &pdev->dev;
0300     struct drm_device *drm_dev;
0301     struct regmap *regmap = NULL;
0302     struct resource res;
0303     void __iomem *base;
0304     int irq;
0305     int ret;
0306 
0307     ret = of_reserved_mem_device_init(dev);
0308     if (ret && ret != -ENODEV) {
0309         dev_err(dev, "Failed to init memory region\n");
0310         goto error_early;
0311     }
0312 
0313     reserved_mem_node = of_parse_phandle(of_node, "memory-region", 0);
0314     if (reserved_mem_node) {
0315         reserved_mem = of_reserved_mem_lookup(reserved_mem_node);
0316         of_node_put(reserved_mem_node);
0317     }
0318 
0319     /* Get regmap from parent if available. */
0320     if (of_node->parent)
0321         regmap = syscon_node_to_regmap(of_node->parent);
0322 
0323     /* Register our own regmap otherwise. */
0324     if (IS_ERR_OR_NULL(regmap)) {
0325         ret = of_address_to_resource(of_node, 0, &res);
0326         if (ret) {
0327             dev_err(dev, "Failed to get resource from address\n");
0328             goto error_reserved_mem;
0329         }
0330 
0331         base = devm_ioremap_resource(dev, &res);
0332         if (IS_ERR(base)) {
0333             dev_err(dev, "Failed to map I/O base\n");
0334             ret = PTR_ERR(base);
0335             goto error_reserved_mem;
0336         }
0337 
0338         logicvc_drm_regmap_config.max_register = resource_size(&res) -
0339                              4;
0340 
0341         regmap = devm_regmap_init_mmio(dev, base,
0342                            &logicvc_drm_regmap_config);
0343         if (IS_ERR(regmap)) {
0344             dev_err(dev, "Failed to create regmap for I/O\n");
0345             ret = PTR_ERR(regmap);
0346             goto error_reserved_mem;
0347         }
0348     }
0349 
0350     irq = platform_get_irq(pdev, 0);
0351     if (irq < 0) {
0352         ret = -ENODEV;
0353         goto error_reserved_mem;
0354     }
0355 
0356     logicvc = devm_drm_dev_alloc(dev, &logicvc_drm_driver,
0357                      struct logicvc_drm, drm_dev);
0358     if (IS_ERR(logicvc)) {
0359         ret = PTR_ERR(logicvc);
0360         goto error_reserved_mem;
0361     }
0362 
0363     platform_set_drvdata(pdev, logicvc);
0364     drm_dev = &logicvc->drm_dev;
0365 
0366     logicvc->regmap = regmap;
0367     INIT_LIST_HEAD(&logicvc->layers_list);
0368 
0369     caps = logicvc_drm_caps_match(logicvc);
0370     if (!caps) {
0371         ret = -EINVAL;
0372         goto error_reserved_mem;
0373     }
0374 
0375     logicvc->caps = caps;
0376 
0377     if (reserved_mem)
0378         logicvc->reserved_mem_base = reserved_mem->base;
0379 
0380     ret = logicvc_clocks_prepare(logicvc);
0381     if (ret) {
0382         drm_err(drm_dev, "Failed to prepare clocks\n");
0383         goto error_reserved_mem;
0384     }
0385 
0386     ret = devm_request_irq(dev, irq, logicvc_drm_irq_handler, 0,
0387                    dev_name(dev), logicvc);
0388     if (ret) {
0389         drm_err(drm_dev, "Failed to request IRQ\n");
0390         goto error_clocks;
0391     }
0392 
0393     ret = logicvc_drm_config_parse(logicvc);
0394     if (ret && ret != -ENODEV) {
0395         drm_err(drm_dev, "Failed to parse config\n");
0396         goto error_clocks;
0397     }
0398 
0399     ret = drmm_mode_config_init(drm_dev);
0400     if (ret) {
0401         drm_err(drm_dev, "Failed to init mode config\n");
0402         goto error_clocks;
0403     }
0404 
0405     ret = logicvc_layers_init(logicvc);
0406     if (ret) {
0407         drm_err(drm_dev, "Failed to initialize layers\n");
0408         goto error_clocks;
0409     }
0410 
0411     ret = logicvc_crtc_init(logicvc);
0412     if (ret) {
0413         drm_err(drm_dev, "Failed to initialize CRTC\n");
0414         goto error_clocks;
0415     }
0416 
0417     logicvc_layers_attach_crtc(logicvc);
0418 
0419     ret = logicvc_interface_init(logicvc);
0420     if (ret) {
0421         if (ret != -EPROBE_DEFER)
0422             drm_err(drm_dev, "Failed to initialize interface\n");
0423 
0424         goto error_clocks;
0425     }
0426 
0427     logicvc_interface_attach_crtc(logicvc);
0428 
0429     ret = logicvc_mode_init(logicvc);
0430     if (ret) {
0431         drm_err(drm_dev, "Failed to initialize KMS\n");
0432         goto error_clocks;
0433     }
0434 
0435     ret = drm_dev_register(drm_dev, 0);
0436     if (ret) {
0437         drm_err(drm_dev, "Failed to register DRM device\n");
0438         goto error_mode;
0439     }
0440 
0441     drm_fbdev_generic_setup(drm_dev, drm_dev->mode_config.preferred_depth);
0442 
0443     return 0;
0444 
0445 error_mode:
0446     logicvc_mode_fini(logicvc);
0447 
0448 error_clocks:
0449     logicvc_clocks_unprepare(logicvc);
0450 
0451 error_reserved_mem:
0452     of_reserved_mem_device_release(dev);
0453 
0454 error_early:
0455     return ret;
0456 }
0457 
0458 static int logicvc_drm_remove(struct platform_device *pdev)
0459 {
0460     struct logicvc_drm *logicvc = platform_get_drvdata(pdev);
0461     struct device *dev = &pdev->dev;
0462     struct drm_device *drm_dev = &logicvc->drm_dev;
0463 
0464     drm_dev_unregister(drm_dev);
0465     drm_atomic_helper_shutdown(drm_dev);
0466 
0467     logicvc_mode_fini(logicvc);
0468 
0469     logicvc_clocks_unprepare(logicvc);
0470 
0471     of_reserved_mem_device_release(dev);
0472 
0473     return 0;
0474 }
0475 
0476 static const struct of_device_id logicvc_drm_of_table[] = {
0477     { .compatible = "xylon,logicvc-3.02.a-display" },
0478     { .compatible = "xylon,logicvc-4.01.a-display" },
0479     {},
0480 };
0481 MODULE_DEVICE_TABLE(of, logicvc_drm_of_table);
0482 
0483 static struct platform_driver logicvc_drm_platform_driver = {
0484     .probe      = logicvc_drm_probe,
0485     .remove     = logicvc_drm_remove,
0486     .driver     = {
0487         .name       = "logicvc-drm",
0488         .of_match_table = logicvc_drm_of_table,
0489     },
0490 };
0491 
0492 module_platform_driver(logicvc_drm_platform_driver);
0493 
0494 MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>");
0495 MODULE_DESCRIPTION("Xylon LogiCVC DRM driver");
0496 MODULE_LICENSE("GPL");