1*312fec14SDave Airlie /* 2*312fec14SDave Airlie * Copyright 2012 Red Hat Inc. 3*312fec14SDave Airlie * 4*312fec14SDave Airlie * Permission is hereby granted, free of charge, to any person obtaining a 5*312fec14SDave Airlie * copy of this software and associated documentation files (the 6*312fec14SDave Airlie * "Software"), to deal in the Software without restriction, including 7*312fec14SDave Airlie * without limitation the rights to use, copy, modify, merge, publish, 8*312fec14SDave Airlie * distribute, sub license, and/or sell copies of the Software, and to 9*312fec14SDave Airlie * permit persons to whom the Software is furnished to do so, subject to 10*312fec14SDave Airlie * the following conditions: 11*312fec14SDave Airlie * 12*312fec14SDave Airlie * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13*312fec14SDave Airlie * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14*312fec14SDave Airlie * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 15*312fec14SDave Airlie * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 16*312fec14SDave Airlie * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 17*312fec14SDave Airlie * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 18*312fec14SDave Airlie * USE OR OTHER DEALINGS IN THE SOFTWARE. 19*312fec14SDave Airlie * 20*312fec14SDave Airlie * The above copyright notice and this permission notice (including the 21*312fec14SDave Airlie * next paragraph) shall be included in all copies or substantial portions 22*312fec14SDave Airlie * of the Software. 23*312fec14SDave Airlie * 24*312fec14SDave Airlie */ 25*312fec14SDave Airlie /* 26*312fec14SDave Airlie * Authors: Dave Airlie <airlied@redhat.com> 27*312fec14SDave Airlie */ 28*312fec14SDave Airlie #include <linux/module.h> 29*312fec14SDave Airlie #include <linux/console.h> 30*312fec14SDave Airlie 31*312fec14SDave Airlie #include "drmP.h" 32*312fec14SDave Airlie #include "drm.h" 33*312fec14SDave Airlie #include "drm_crtc_helper.h" 34*312fec14SDave Airlie 35*312fec14SDave Airlie #include "ast_drv.h" 36*312fec14SDave Airlie 37*312fec14SDave Airlie int ast_modeset = -1; 38*312fec14SDave Airlie 39*312fec14SDave Airlie MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); 40*312fec14SDave Airlie module_param_named(modeset, ast_modeset, int, 0400); 41*312fec14SDave Airlie 42*312fec14SDave Airlie #define PCI_VENDOR_ASPEED 0x1a03 43*312fec14SDave Airlie 44*312fec14SDave Airlie static struct drm_driver driver; 45*312fec14SDave Airlie 46*312fec14SDave Airlie #define AST_VGA_DEVICE(id, info) { \ 47*312fec14SDave Airlie .class = PCI_BASE_CLASS_DISPLAY << 16, \ 48*312fec14SDave Airlie .class_mask = 0xff0000, \ 49*312fec14SDave Airlie .vendor = PCI_VENDOR_ASPEED, \ 50*312fec14SDave Airlie .device = id, \ 51*312fec14SDave Airlie .subvendor = PCI_ANY_ID, \ 52*312fec14SDave Airlie .subdevice = PCI_ANY_ID, \ 53*312fec14SDave Airlie .driver_data = (unsigned long) info } 54*312fec14SDave Airlie 55*312fec14SDave Airlie static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { 56*312fec14SDave Airlie AST_VGA_DEVICE(PCI_CHIP_AST2000, NULL), 57*312fec14SDave Airlie AST_VGA_DEVICE(PCI_CHIP_AST2100, NULL), 58*312fec14SDave Airlie /* AST_VGA_DEVICE(PCI_CHIP_AST1180, NULL), - don't bind to 1180 for now */ 59*312fec14SDave Airlie {0, 0, 0}, 60*312fec14SDave Airlie }; 61*312fec14SDave Airlie 62*312fec14SDave Airlie MODULE_DEVICE_TABLE(pci, pciidlist); 63*312fec14SDave Airlie 64*312fec14SDave Airlie static int __devinit 65*312fec14SDave Airlie ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 66*312fec14SDave Airlie { 67*312fec14SDave Airlie return drm_get_pci_dev(pdev, ent, &driver); 68*312fec14SDave Airlie } 69*312fec14SDave Airlie 70*312fec14SDave Airlie static void 71*312fec14SDave Airlie ast_pci_remove(struct pci_dev *pdev) 72*312fec14SDave Airlie { 73*312fec14SDave Airlie struct drm_device *dev = pci_get_drvdata(pdev); 74*312fec14SDave Airlie 75*312fec14SDave Airlie drm_put_dev(dev); 76*312fec14SDave Airlie } 77*312fec14SDave Airlie 78*312fec14SDave Airlie 79*312fec14SDave Airlie 80*312fec14SDave Airlie static int ast_drm_freeze(struct drm_device *dev) 81*312fec14SDave Airlie { 82*312fec14SDave Airlie drm_kms_helper_poll_disable(dev); 83*312fec14SDave Airlie 84*312fec14SDave Airlie pci_save_state(dev->pdev); 85*312fec14SDave Airlie 86*312fec14SDave Airlie console_lock(); 87*312fec14SDave Airlie ast_fbdev_set_suspend(dev, 1); 88*312fec14SDave Airlie console_unlock(); 89*312fec14SDave Airlie return 0; 90*312fec14SDave Airlie } 91*312fec14SDave Airlie 92*312fec14SDave Airlie static int ast_drm_thaw(struct drm_device *dev) 93*312fec14SDave Airlie { 94*312fec14SDave Airlie int error = 0; 95*312fec14SDave Airlie 96*312fec14SDave Airlie ast_post_gpu(dev); 97*312fec14SDave Airlie 98*312fec14SDave Airlie drm_mode_config_reset(dev); 99*312fec14SDave Airlie mutex_lock(&dev->mode_config.mutex); 100*312fec14SDave Airlie drm_helper_resume_force_mode(dev); 101*312fec14SDave Airlie mutex_unlock(&dev->mode_config.mutex); 102*312fec14SDave Airlie 103*312fec14SDave Airlie console_lock(); 104*312fec14SDave Airlie ast_fbdev_set_suspend(dev, 0); 105*312fec14SDave Airlie console_unlock(); 106*312fec14SDave Airlie return error; 107*312fec14SDave Airlie } 108*312fec14SDave Airlie 109*312fec14SDave Airlie static int ast_drm_resume(struct drm_device *dev) 110*312fec14SDave Airlie { 111*312fec14SDave Airlie int ret; 112*312fec14SDave Airlie 113*312fec14SDave Airlie if (pci_enable_device(dev->pdev)) 114*312fec14SDave Airlie return -EIO; 115*312fec14SDave Airlie 116*312fec14SDave Airlie ret = ast_drm_thaw(dev); 117*312fec14SDave Airlie if (ret) 118*312fec14SDave Airlie return ret; 119*312fec14SDave Airlie 120*312fec14SDave Airlie drm_kms_helper_poll_enable(dev); 121*312fec14SDave Airlie return 0; 122*312fec14SDave Airlie } 123*312fec14SDave Airlie 124*312fec14SDave Airlie static int ast_pm_suspend(struct device *dev) 125*312fec14SDave Airlie { 126*312fec14SDave Airlie struct pci_dev *pdev = to_pci_dev(dev); 127*312fec14SDave Airlie struct drm_device *ddev = pci_get_drvdata(pdev); 128*312fec14SDave Airlie int error; 129*312fec14SDave Airlie 130*312fec14SDave Airlie error = ast_drm_freeze(ddev); 131*312fec14SDave Airlie if (error) 132*312fec14SDave Airlie return error; 133*312fec14SDave Airlie 134*312fec14SDave Airlie pci_disable_device(pdev); 135*312fec14SDave Airlie pci_set_power_state(pdev, PCI_D3hot); 136*312fec14SDave Airlie return 0; 137*312fec14SDave Airlie } 138*312fec14SDave Airlie static int ast_pm_resume(struct device *dev) 139*312fec14SDave Airlie { 140*312fec14SDave Airlie struct pci_dev *pdev = to_pci_dev(dev); 141*312fec14SDave Airlie struct drm_device *ddev = pci_get_drvdata(pdev); 142*312fec14SDave Airlie return ast_drm_resume(ddev); 143*312fec14SDave Airlie } 144*312fec14SDave Airlie 145*312fec14SDave Airlie static int ast_pm_freeze(struct device *dev) 146*312fec14SDave Airlie { 147*312fec14SDave Airlie struct pci_dev *pdev = to_pci_dev(dev); 148*312fec14SDave Airlie struct drm_device *ddev = pci_get_drvdata(pdev); 149*312fec14SDave Airlie 150*312fec14SDave Airlie if (!ddev || !ddev->dev_private) 151*312fec14SDave Airlie return -ENODEV; 152*312fec14SDave Airlie return ast_drm_freeze(ddev); 153*312fec14SDave Airlie 154*312fec14SDave Airlie } 155*312fec14SDave Airlie 156*312fec14SDave Airlie static int ast_pm_thaw(struct device *dev) 157*312fec14SDave Airlie { 158*312fec14SDave Airlie struct pci_dev *pdev = to_pci_dev(dev); 159*312fec14SDave Airlie struct drm_device *ddev = pci_get_drvdata(pdev); 160*312fec14SDave Airlie return ast_drm_thaw(ddev); 161*312fec14SDave Airlie } 162*312fec14SDave Airlie 163*312fec14SDave Airlie static int ast_pm_poweroff(struct device *dev) 164*312fec14SDave Airlie { 165*312fec14SDave Airlie struct pci_dev *pdev = to_pci_dev(dev); 166*312fec14SDave Airlie struct drm_device *ddev = pci_get_drvdata(pdev); 167*312fec14SDave Airlie 168*312fec14SDave Airlie return ast_drm_freeze(ddev); 169*312fec14SDave Airlie } 170*312fec14SDave Airlie 171*312fec14SDave Airlie static const struct dev_pm_ops ast_pm_ops = { 172*312fec14SDave Airlie .suspend = ast_pm_suspend, 173*312fec14SDave Airlie .resume = ast_pm_resume, 174*312fec14SDave Airlie .freeze = ast_pm_freeze, 175*312fec14SDave Airlie .thaw = ast_pm_thaw, 176*312fec14SDave Airlie .poweroff = ast_pm_poweroff, 177*312fec14SDave Airlie .restore = ast_pm_resume, 178*312fec14SDave Airlie }; 179*312fec14SDave Airlie 180*312fec14SDave Airlie static struct pci_driver ast_pci_driver = { 181*312fec14SDave Airlie .name = DRIVER_NAME, 182*312fec14SDave Airlie .id_table = pciidlist, 183*312fec14SDave Airlie .probe = ast_pci_probe, 184*312fec14SDave Airlie .remove = ast_pci_remove, 185*312fec14SDave Airlie .driver.pm = &ast_pm_ops, 186*312fec14SDave Airlie }; 187*312fec14SDave Airlie 188*312fec14SDave Airlie static const struct file_operations ast_fops = { 189*312fec14SDave Airlie .owner = THIS_MODULE, 190*312fec14SDave Airlie .open = drm_open, 191*312fec14SDave Airlie .release = drm_release, 192*312fec14SDave Airlie .unlocked_ioctl = drm_ioctl, 193*312fec14SDave Airlie .mmap = ast_mmap, 194*312fec14SDave Airlie .poll = drm_poll, 195*312fec14SDave Airlie .fasync = drm_fasync, 196*312fec14SDave Airlie .read = drm_read, 197*312fec14SDave Airlie }; 198*312fec14SDave Airlie 199*312fec14SDave Airlie static struct drm_driver driver = { 200*312fec14SDave Airlie .driver_features = DRIVER_USE_MTRR | DRIVER_MODESET | DRIVER_GEM, 201*312fec14SDave Airlie .dev_priv_size = 0, 202*312fec14SDave Airlie 203*312fec14SDave Airlie .load = ast_driver_load, 204*312fec14SDave Airlie .unload = ast_driver_unload, 205*312fec14SDave Airlie 206*312fec14SDave Airlie .fops = &ast_fops, 207*312fec14SDave Airlie .name = DRIVER_NAME, 208*312fec14SDave Airlie .desc = DRIVER_DESC, 209*312fec14SDave Airlie .date = DRIVER_DATE, 210*312fec14SDave Airlie .major = DRIVER_MAJOR, 211*312fec14SDave Airlie .minor = DRIVER_MINOR, 212*312fec14SDave Airlie .patchlevel = DRIVER_PATCHLEVEL, 213*312fec14SDave Airlie 214*312fec14SDave Airlie .gem_init_object = ast_gem_init_object, 215*312fec14SDave Airlie .gem_free_object = ast_gem_free_object, 216*312fec14SDave Airlie .dumb_create = ast_dumb_create, 217*312fec14SDave Airlie .dumb_map_offset = ast_dumb_mmap_offset, 218*312fec14SDave Airlie .dumb_destroy = ast_dumb_destroy, 219*312fec14SDave Airlie 220*312fec14SDave Airlie }; 221*312fec14SDave Airlie 222*312fec14SDave Airlie static int __init ast_init(void) 223*312fec14SDave Airlie { 224*312fec14SDave Airlie if (vgacon_text_force() && ast_modeset == -1) 225*312fec14SDave Airlie return -EINVAL; 226*312fec14SDave Airlie 227*312fec14SDave Airlie if (ast_modeset == 0) 228*312fec14SDave Airlie return -EINVAL; 229*312fec14SDave Airlie return drm_pci_init(&driver, &ast_pci_driver); 230*312fec14SDave Airlie } 231*312fec14SDave Airlie static void __exit ast_exit(void) 232*312fec14SDave Airlie { 233*312fec14SDave Airlie drm_pci_exit(&driver, &ast_pci_driver); 234*312fec14SDave Airlie } 235*312fec14SDave Airlie 236*312fec14SDave Airlie module_init(ast_init); 237*312fec14SDave Airlie module_exit(ast_exit); 238*312fec14SDave Airlie 239*312fec14SDave Airlie MODULE_AUTHOR(DRIVER_AUTHOR); 240*312fec14SDave Airlie MODULE_DESCRIPTION(DRIVER_DESC); 241*312fec14SDave Airlie MODULE_LICENSE("GPL and additional rights"); 242*312fec14SDave Airlie 243