Home | History | Annotate | Line # | Download | only in ast
      1 /*	$NetBSD: ast_drv.c,v 1.4 2021/12/18 23:45:27 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2012 Red Hat Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
     17  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
     18  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     19  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
     20  * USE OR OTHER DEALINGS IN THE SOFTWARE.
     21  *
     22  * The above copyright notice and this permission notice (including the
     23  * next paragraph) shall be included in all copies or substantial portions
     24  * of the Software.
     25  *
     26  */
     27 /*
     28  * Authors: Dave Airlie <airlied (at) redhat.com>
     29  */
     30 
     31 #include <sys/cdefs.h>
     32 __KERNEL_RCSID(0, "$NetBSD: ast_drv.c,v 1.4 2021/12/18 23:45:27 riastradh Exp $");
     33 
     34 #include <linux/console.h>
     35 #include <linux/module.h>
     36 #include <linux/pci.h>
     37 
     38 #include <drm/drm_crtc_helper.h>
     39 #include <drm/drm_drv.h>
     40 #include <drm/drm_gem_vram_helper.h>
     41 #include <drm/drm_probe_helper.h>
     42 
     43 #include "ast_drv.h"
     44 
     45 int ast_modeset = -1;
     46 
     47 MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
     48 module_param_named(modeset, ast_modeset, int, 0400);
     49 
     50 #define PCI_VENDOR_ASPEED 0x1a03
     51 
     52 static struct drm_driver driver;
     53 
     54 #define AST_VGA_DEVICE(id, info) {		\
     55 	.class = PCI_BASE_CLASS_DISPLAY << 16,	\
     56 	.class_mask = 0xff0000,			\
     57 	.vendor = PCI_VENDOR_ASPEED,			\
     58 	.device = id,				\
     59 	.subvendor = PCI_ANY_ID,		\
     60 	.subdevice = PCI_ANY_ID,		\
     61 	.driver_data = (unsigned long) info }
     62 
     63 static const struct pci_device_id pciidlist[] = {
     64 	AST_VGA_DEVICE(PCI_CHIP_AST2000, NULL),
     65 	AST_VGA_DEVICE(PCI_CHIP_AST2100, NULL),
     66 	/*	AST_VGA_DEVICE(PCI_CHIP_AST1180, NULL), - don't bind to 1180 for now */
     67 	{0, 0, 0},
     68 };
     69 
     70 MODULE_DEVICE_TABLE(pci, pciidlist);
     71 
     72 static void ast_kick_out_firmware_fb(struct pci_dev *pdev)
     73 {
     74 	struct apertures_struct *ap;
     75 	bool primary = false;
     76 
     77 	ap = alloc_apertures(1);
     78 	if (!ap)
     79 		return;
     80 
     81 	ap->ranges[0].base = pci_resource_start(pdev, 0);
     82 	ap->ranges[0].size = pci_resource_len(pdev, 0);
     83 
     84 #ifdef CONFIG_X86
     85 	primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
     86 #endif
     87 	drm_fb_helper_remove_conflicting_framebuffers(ap, "astdrmfb", primary);
     88 	kfree(ap);
     89 }
     90 
     91 static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
     92 {
     93 	struct drm_device *dev;
     94 	int ret;
     95 
     96 	ast_kick_out_firmware_fb(pdev);
     97 
     98 	ret = pci_enable_device(pdev);
     99 	if (ret)
    100 		return ret;
    101 
    102 	dev = drm_dev_alloc(&driver, &pdev->dev);
    103 	if (IS_ERR(dev)) {
    104 		ret = PTR_ERR(dev);
    105 		goto err_pci_disable_device;
    106 	}
    107 
    108 	dev->pdev = pdev;
    109 	pci_set_drvdata(pdev, dev);
    110 
    111 	ret = ast_driver_load(dev, ent->driver_data);
    112 	if (ret)
    113 		goto err_drm_dev_put;
    114 
    115 	ret = drm_dev_register(dev, ent->driver_data);
    116 	if (ret)
    117 		goto err_ast_driver_unload;
    118 
    119 	return 0;
    120 
    121 err_ast_driver_unload:
    122 	ast_driver_unload(dev);
    123 err_drm_dev_put:
    124 	drm_dev_put(dev);
    125 err_pci_disable_device:
    126 	pci_disable_device(pdev);
    127 	return ret;
    128 
    129 }
    130 
    131 static void
    132 ast_pci_remove(struct pci_dev *pdev)
    133 {
    134 	struct drm_device *dev = pci_get_drvdata(pdev);
    135 
    136 	drm_dev_unregister(dev);
    137 	ast_driver_unload(dev);
    138 	drm_dev_put(dev);
    139 }
    140 
    141 static int ast_drm_freeze(struct drm_device *dev)
    142 {
    143 	int error;
    144 
    145 	error = drm_mode_config_helper_suspend(dev);
    146 	if (error)
    147 		return error;
    148 	pci_save_state(dev->pdev);
    149 	return 0;
    150 }
    151 
    152 static int ast_drm_thaw(struct drm_device *dev)
    153 {
    154 	ast_post_gpu(dev);
    155 
    156 	return drm_mode_config_helper_resume(dev);
    157 }
    158 
    159 static int ast_drm_resume(struct drm_device *dev)
    160 {
    161 	int ret;
    162 
    163 	if (pci_enable_device(dev->pdev))
    164 		return -EIO;
    165 
    166 	ret = ast_drm_thaw(dev);
    167 	if (ret)
    168 		return ret;
    169 	return 0;
    170 }
    171 
    172 static int ast_pm_suspend(struct device *dev)
    173 {
    174 	struct pci_dev *pdev = to_pci_dev(dev);
    175 	struct drm_device *ddev = pci_get_drvdata(pdev);
    176 	int error;
    177 
    178 	error = ast_drm_freeze(ddev);
    179 	if (error)
    180 		return error;
    181 
    182 	pci_disable_device(pdev);
    183 	pci_set_power_state(pdev, PCI_D3hot);
    184 	return 0;
    185 }
    186 
    187 static int ast_pm_resume(struct device *dev)
    188 {
    189 	struct pci_dev *pdev = to_pci_dev(dev);
    190 	struct drm_device *ddev = pci_get_drvdata(pdev);
    191 	return ast_drm_resume(ddev);
    192 }
    193 
    194 static int ast_pm_freeze(struct device *dev)
    195 {
    196 	struct pci_dev *pdev = to_pci_dev(dev);
    197 	struct drm_device *ddev = pci_get_drvdata(pdev);
    198 
    199 	if (!ddev || !ddev->dev_private)
    200 		return -ENODEV;
    201 	return ast_drm_freeze(ddev);
    202 }
    203 
    204 static int ast_pm_thaw(struct device *dev)
    205 {
    206 	struct pci_dev *pdev = to_pci_dev(dev);
    207 	struct drm_device *ddev = pci_get_drvdata(pdev);
    208 	return ast_drm_thaw(ddev);
    209 }
    210 
    211 static int ast_pm_poweroff(struct device *dev)
    212 {
    213 	struct pci_dev *pdev = to_pci_dev(dev);
    214 	struct drm_device *ddev = pci_get_drvdata(pdev);
    215 
    216 	return ast_drm_freeze(ddev);
    217 }
    218 
    219 static const struct dev_pm_ops ast_pm_ops = {
    220 	.suspend = ast_pm_suspend,
    221 	.resume = ast_pm_resume,
    222 	.freeze = ast_pm_freeze,
    223 	.thaw = ast_pm_thaw,
    224 	.poweroff = ast_pm_poweroff,
    225 	.restore = ast_pm_resume,
    226 };
    227 
    228 static struct pci_driver ast_pci_driver = {
    229 	.name = DRIVER_NAME,
    230 	.id_table = pciidlist,
    231 	.probe = ast_pci_probe,
    232 	.remove = ast_pci_remove,
    233 	.driver.pm = &ast_pm_ops,
    234 };
    235 
    236 DEFINE_DRM_GEM_FOPS(ast_fops);
    237 
    238 static struct drm_driver driver = {
    239 	.driver_features = DRIVER_ATOMIC |
    240 			   DRIVER_GEM |
    241 			   DRIVER_MODESET,
    242 
    243 	.fops = &ast_fops,
    244 	.name = DRIVER_NAME,
    245 	.desc = DRIVER_DESC,
    246 	.date = DRIVER_DATE,
    247 	.major = DRIVER_MAJOR,
    248 	.minor = DRIVER_MINOR,
    249 	.patchlevel = DRIVER_PATCHLEVEL,
    250 
    251 	DRM_GEM_VRAM_DRIVER
    252 };
    253 
    254 static int __init ast_init(void)
    255 {
    256 	if (vgacon_text_force() && ast_modeset == -1)
    257 		return -EINVAL;
    258 
    259 	if (ast_modeset == 0)
    260 		return -EINVAL;
    261 	return pci_register_driver(&ast_pci_driver);
    262 }
    263 static void __exit ast_exit(void)
    264 {
    265 	pci_unregister_driver(&ast_pci_driver);
    266 }
    267 
    268 module_init(ast_init);
    269 module_exit(ast_exit);
    270 
    271 MODULE_AUTHOR(DRIVER_AUTHOR);
    272 MODULE_DESCRIPTION(DRIVER_DESC);
    273 MODULE_LICENSE("GPL and additional rights");
    274 
    275