Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) STMicroelectronics SA 2014
0004  * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
0005  */
0006 
0007 #include <linux/component.h>
0008 #include <linux/dma-mapping.h>
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <linux/of_platform.h>
0012 
0013 #include <drm/drm_atomic.h>
0014 #include <drm/drm_atomic_helper.h>
0015 #include <drm/drm_debugfs.h>
0016 #include <drm/drm_drv.h>
0017 #include <drm/drm_fb_cma_helper.h>
0018 #include <drm/drm_fb_helper.h>
0019 #include <drm/drm_gem_cma_helper.h>
0020 #include <drm/drm_gem_framebuffer_helper.h>
0021 #include <drm/drm_of.h>
0022 #include <drm/drm_probe_helper.h>
0023 
0024 #include "sti_drv.h"
0025 #include "sti_plane.h"
0026 
0027 #define DRIVER_NAME "sti"
0028 #define DRIVER_DESC "STMicroelectronics SoC DRM"
0029 #define DRIVER_DATE "20140601"
0030 #define DRIVER_MAJOR    1
0031 #define DRIVER_MINOR    0
0032 
0033 #define STI_MAX_FB_HEIGHT   4096
0034 #define STI_MAX_FB_WIDTH    4096
0035 
0036 static int sti_drm_fps_get(void *data, u64 *val)
0037 {
0038     struct drm_device *drm_dev = data;
0039     struct drm_plane *p;
0040     unsigned int i = 0;
0041 
0042     *val = 0;
0043     list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
0044         struct sti_plane *plane = to_sti_plane(p);
0045 
0046         *val |= plane->fps_info.output << i;
0047         i++;
0048     }
0049 
0050     return 0;
0051 }
0052 
0053 static int sti_drm_fps_set(void *data, u64 val)
0054 {
0055     struct drm_device *drm_dev = data;
0056     struct drm_plane *p;
0057     unsigned int i = 0;
0058 
0059     list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
0060         struct sti_plane *plane = to_sti_plane(p);
0061 
0062         memset(&plane->fps_info, 0, sizeof(plane->fps_info));
0063         plane->fps_info.output = (val >> i) & 1;
0064 
0065         i++;
0066     }
0067 
0068     return 0;
0069 }
0070 
0071 DEFINE_SIMPLE_ATTRIBUTE(sti_drm_fps_fops,
0072             sti_drm_fps_get, sti_drm_fps_set, "%llu\n");
0073 
0074 static int sti_drm_fps_dbg_show(struct seq_file *s, void *data)
0075 {
0076     struct drm_info_node *node = s->private;
0077     struct drm_device *dev = node->minor->dev;
0078     struct drm_plane *p;
0079 
0080     list_for_each_entry(p, &dev->mode_config.plane_list, head) {
0081         struct sti_plane *plane = to_sti_plane(p);
0082 
0083         seq_printf(s, "%s%s\n",
0084                plane->fps_info.fps_str,
0085                plane->fps_info.fips_str);
0086     }
0087 
0088     return 0;
0089 }
0090 
0091 static struct drm_info_list sti_drm_dbg_list[] = {
0092     {"fps_get", sti_drm_fps_dbg_show, 0},
0093 };
0094 
0095 static void sti_drm_dbg_init(struct drm_minor *minor)
0096 {
0097     drm_debugfs_create_files(sti_drm_dbg_list,
0098                  ARRAY_SIZE(sti_drm_dbg_list),
0099                  minor->debugfs_root, minor);
0100 
0101     debugfs_create_file("fps_show", S_IRUGO | S_IWUSR, minor->debugfs_root,
0102                 minor->dev, &sti_drm_fps_fops);
0103 
0104     DRM_INFO("%s: debugfs installed\n", DRIVER_NAME);
0105 }
0106 
0107 static const struct drm_mode_config_funcs sti_mode_config_funcs = {
0108     .fb_create = drm_gem_fb_create,
0109     .atomic_check = drm_atomic_helper_check,
0110     .atomic_commit = drm_atomic_helper_commit,
0111 };
0112 
0113 static void sti_mode_config_init(struct drm_device *dev)
0114 {
0115     dev->mode_config.min_width = 0;
0116     dev->mode_config.min_height = 0;
0117 
0118     /*
0119      * set max width and height as default value.
0120      * this value would be used to check framebuffer size limitation
0121      * at drm_mode_addfb().
0122      */
0123     dev->mode_config.max_width = STI_MAX_FB_WIDTH;
0124     dev->mode_config.max_height = STI_MAX_FB_HEIGHT;
0125 
0126     dev->mode_config.funcs = &sti_mode_config_funcs;
0127 
0128     dev->mode_config.normalize_zpos = true;
0129 }
0130 
0131 DEFINE_DRM_GEM_CMA_FOPS(sti_driver_fops);
0132 
0133 static const struct drm_driver sti_driver = {
0134     .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
0135     .fops = &sti_driver_fops,
0136     DRM_GEM_CMA_DRIVER_OPS,
0137 
0138     .debugfs_init = sti_drm_dbg_init,
0139 
0140     .name = DRIVER_NAME,
0141     .desc = DRIVER_DESC,
0142     .date = DRIVER_DATE,
0143     .major = DRIVER_MAJOR,
0144     .minor = DRIVER_MINOR,
0145 };
0146 
0147 static int sti_init(struct drm_device *ddev)
0148 {
0149     struct sti_private *private;
0150 
0151     private = kzalloc(sizeof(*private), GFP_KERNEL);
0152     if (!private)
0153         return -ENOMEM;
0154 
0155     ddev->dev_private = (void *)private;
0156     dev_set_drvdata(ddev->dev, ddev);
0157     private->drm_dev = ddev;
0158 
0159     drm_mode_config_init(ddev);
0160 
0161     sti_mode_config_init(ddev);
0162 
0163     drm_kms_helper_poll_init(ddev);
0164 
0165     return 0;
0166 }
0167 
0168 static void sti_cleanup(struct drm_device *ddev)
0169 {
0170     struct sti_private *private = ddev->dev_private;
0171 
0172     drm_kms_helper_poll_fini(ddev);
0173     drm_atomic_helper_shutdown(ddev);
0174     drm_mode_config_cleanup(ddev);
0175     component_unbind_all(ddev->dev, ddev);
0176     kfree(private);
0177     ddev->dev_private = NULL;
0178 }
0179 
0180 static int sti_bind(struct device *dev)
0181 {
0182     struct drm_device *ddev;
0183     int ret;
0184 
0185     ddev = drm_dev_alloc(&sti_driver, dev);
0186     if (IS_ERR(ddev))
0187         return PTR_ERR(ddev);
0188 
0189     ret = sti_init(ddev);
0190     if (ret)
0191         goto err_drm_dev_put;
0192 
0193     ret = component_bind_all(ddev->dev, ddev);
0194     if (ret)
0195         goto err_cleanup;
0196 
0197     ret = drm_dev_register(ddev, 0);
0198     if (ret)
0199         goto err_cleanup;
0200 
0201     drm_mode_config_reset(ddev);
0202 
0203     drm_fbdev_generic_setup(ddev, 32);
0204 
0205     return 0;
0206 
0207 err_cleanup:
0208     sti_cleanup(ddev);
0209 err_drm_dev_put:
0210     drm_dev_put(ddev);
0211     return ret;
0212 }
0213 
0214 static void sti_unbind(struct device *dev)
0215 {
0216     struct drm_device *ddev = dev_get_drvdata(dev);
0217 
0218     drm_dev_unregister(ddev);
0219     sti_cleanup(ddev);
0220     drm_dev_put(ddev);
0221 }
0222 
0223 static const struct component_master_ops sti_ops = {
0224     .bind = sti_bind,
0225     .unbind = sti_unbind,
0226 };
0227 
0228 static int sti_platform_probe(struct platform_device *pdev)
0229 {
0230     struct device *dev = &pdev->dev;
0231     struct device_node *node = dev->of_node;
0232     struct device_node *child_np;
0233     struct component_match *match = NULL;
0234 
0235     dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
0236 
0237     devm_of_platform_populate(dev);
0238 
0239     child_np = of_get_next_available_child(node, NULL);
0240 
0241     while (child_np) {
0242         drm_of_component_match_add(dev, &match, component_compare_of,
0243                        child_np);
0244         child_np = of_get_next_available_child(node, child_np);
0245     }
0246 
0247     return component_master_add_with_match(dev, &sti_ops, match);
0248 }
0249 
0250 static int sti_platform_remove(struct platform_device *pdev)
0251 {
0252     component_master_del(&pdev->dev, &sti_ops);
0253 
0254     return 0;
0255 }
0256 
0257 static const struct of_device_id sti_dt_ids[] = {
0258     { .compatible = "st,sti-display-subsystem", },
0259     { /* end node */ },
0260 };
0261 MODULE_DEVICE_TABLE(of, sti_dt_ids);
0262 
0263 static struct platform_driver sti_platform_driver = {
0264     .probe = sti_platform_probe,
0265     .remove = sti_platform_remove,
0266     .driver = {
0267         .name = DRIVER_NAME,
0268         .of_match_table = sti_dt_ids,
0269     },
0270 };
0271 
0272 static struct platform_driver * const drivers[] = {
0273     &sti_tvout_driver,
0274     &sti_hqvdp_driver,
0275     &sti_hdmi_driver,
0276     &sti_hda_driver,
0277     &sti_dvo_driver,
0278     &sti_vtg_driver,
0279     &sti_compositor_driver,
0280     &sti_platform_driver,
0281 };
0282 
0283 static int sti_drm_init(void)
0284 {
0285     if (drm_firmware_drivers_only())
0286         return -ENODEV;
0287 
0288     return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
0289 }
0290 module_init(sti_drm_init);
0291 
0292 static void sti_drm_exit(void)
0293 {
0294     platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
0295 }
0296 module_exit(sti_drm_exit);
0297 
0298 MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
0299 MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
0300 MODULE_LICENSE("GPL");