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@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