xref: /openbmc/linux/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
25e0df3a0SRongrong Zou /* Hisilicon Hibmc SoC drm driver
35e0df3a0SRongrong Zou  *
45e0df3a0SRongrong Zou  * Based on the bochs drm driver.
55e0df3a0SRongrong Zou  *
65e0df3a0SRongrong Zou  * Copyright (c) 2016 Huawei Limited.
75e0df3a0SRongrong Zou  *
85e0df3a0SRongrong Zou  * Author:
95e0df3a0SRongrong Zou  *	Rongrong Zou <zourongrong@huawei.com>
105e0df3a0SRongrong Zou  *	Rongrong Zou <zourongrong@gmail.com>
115e0df3a0SRongrong Zou  *	Jianhua Li <lijianhua@huawei.com>
125e0df3a0SRongrong Zou  */
135e0df3a0SRongrong Zou 
1470c7fe17STian Tao #include <linux/module.h>
1540b4db43SSam Ravnborg #include <linux/pci.h>
165e0df3a0SRongrong Zou 
176848c291SThomas Zimmermann #include <drm/drm_aperture.h>
18da52605eSRongrong Zou #include <drm/drm_atomic_helper.h>
1940b4db43SSam Ravnborg #include <drm/drm_drv.h>
208ab59da2SThomas Zimmermann #include <drm/drm_fbdev_generic.h>
21552a77baSTian Tao #include <drm/drm_gem_framebuffer_helper.h>
2240b4db43SSam Ravnborg #include <drm/drm_gem_vram_helper.h>
23cdf01268STian Tao #include <drm/drm_managed.h>
242075a734SThomas Zimmermann #include <drm/drm_module.h>
2540b4db43SSam Ravnborg #include <drm/drm_vblank.h>
26da52605eSRongrong Zou 
275e0df3a0SRongrong Zou #include "hibmc_drm_drv.h"
285e0df3a0SRongrong Zou #include "hibmc_drm_regs.h"
295e0df3a0SRongrong Zou 
3002f64b2dSGerd Hoffmann DEFINE_DRM_GEM_FOPS(hibmc_fops);
315e0df3a0SRongrong Zou 
hibmc_interrupt(int irq,void * arg)3239a364a1SThomas Zimmermann static irqreturn_t hibmc_interrupt(int irq, void *arg)
331d98b916SRongrong Zou {
341d98b916SRongrong Zou 	struct drm_device *dev = (struct drm_device *)arg;
35c7a39927STian Tao 	struct hibmc_drm_private *priv = to_hibmc_drm_private(dev);
361d98b916SRongrong Zou 	u32 status;
371d98b916SRongrong Zou 
381d98b916SRongrong Zou 	status = readl(priv->mmio + HIBMC_RAW_INTERRUPT);
391d98b916SRongrong Zou 
401d98b916SRongrong Zou 	if (status & HIBMC_RAW_INTERRUPT_VBLANK(1)) {
411d98b916SRongrong Zou 		writel(HIBMC_RAW_INTERRUPT_VBLANK(1),
421d98b916SRongrong Zou 		       priv->mmio + HIBMC_RAW_INTERRUPT);
431d98b916SRongrong Zou 		drm_handle_vblank(dev, 0);
441d98b916SRongrong Zou 	}
451d98b916SRongrong Zou 
461d98b916SRongrong Zou 	return IRQ_HANDLED;
475e0df3a0SRongrong Zou }
485e0df3a0SRongrong Zou 
hibmc_dumb_create(struct drm_file * file,struct drm_device * dev,struct drm_mode_create_dumb * args)49552a77baSTian Tao static int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev,
50552a77baSTian Tao 			     struct drm_mode_create_dumb *args)
51552a77baSTian Tao {
52552a77baSTian Tao 	return drm_gem_vram_fill_create_dumb(file, dev, 0, 128, args);
53552a77baSTian Tao }
54552a77baSTian Tao 
5570a59dd8SDaniel Vetter static const struct drm_driver hibmc_driver = {
565b38e747SDaniel Vetter 	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
575e0df3a0SRongrong Zou 	.fops			= &hibmc_fops,
585e0df3a0SRongrong Zou 	.name			= "hibmc",
595e0df3a0SRongrong Zou 	.date			= "20160828",
605e0df3a0SRongrong Zou 	.desc			= "hibmc drm driver",
615e0df3a0SRongrong Zou 	.major			= 1,
625e0df3a0SRongrong Zou 	.minor			= 0,
63de2318f6SThomas Zimmermann 	.debugfs_init		= drm_vram_mm_debugfs_init,
64e4daebc7SRongrong Zou 	.dumb_create            = hibmc_dumb_create,
65ede0c69cSThomas Zimmermann 	.dumb_map_offset        = drm_gem_ttm_dumb_map_offset,
665e0df3a0SRongrong Zou };
675e0df3a0SRongrong Zou 
hibmc_pm_suspend(struct device * dev)68b61abd49SArnd Bergmann static int __maybe_unused hibmc_pm_suspend(struct device *dev)
695e0df3a0SRongrong Zou {
70bda4a850SChuhong Yuan 	struct drm_device *drm_dev = dev_get_drvdata(dev);
71da52605eSRongrong Zou 
72081d0571SSouptick Joarder 	return drm_mode_config_helper_suspend(drm_dev);
735e0df3a0SRongrong Zou }
745e0df3a0SRongrong Zou 
hibmc_pm_resume(struct device * dev)75b61abd49SArnd Bergmann static int  __maybe_unused hibmc_pm_resume(struct device *dev)
765e0df3a0SRongrong Zou {
77bda4a850SChuhong Yuan 	struct drm_device *drm_dev = dev_get_drvdata(dev);
78da52605eSRongrong Zou 
79081d0571SSouptick Joarder 	return drm_mode_config_helper_resume(drm_dev);
805e0df3a0SRongrong Zou }
815e0df3a0SRongrong Zou 
825e0df3a0SRongrong Zou static const struct dev_pm_ops hibmc_pm_ops = {
835e0df3a0SRongrong Zou 	SET_SYSTEM_SLEEP_PM_OPS(hibmc_pm_suspend,
845e0df3a0SRongrong Zou 				hibmc_pm_resume)
855e0df3a0SRongrong Zou };
865e0df3a0SRongrong Zou 
87552a77baSTian Tao static const struct drm_mode_config_funcs hibmc_mode_funcs = {
88552a77baSTian Tao 	.mode_valid = drm_vram_helper_mode_valid,
89552a77baSTian Tao 	.atomic_check = drm_atomic_helper_check,
90552a77baSTian Tao 	.atomic_commit = drm_atomic_helper_commit,
91552a77baSTian Tao 	.fb_create = drm_gem_fb_create,
92552a77baSTian Tao };
93552a77baSTian Tao 
hibmc_kms_init(struct hibmc_drm_private * priv)94da52605eSRongrong Zou static int hibmc_kms_init(struct hibmc_drm_private *priv)
95da52605eSRongrong Zou {
96770729f7STian Tao 	struct drm_device *dev = &priv->dev;
97da52605eSRongrong Zou 	int ret;
98da52605eSRongrong Zou 
991c1b5bd4STian Tao 	ret = drmm_mode_config_init(dev);
1001c1b5bd4STian Tao 	if (ret)
1011c1b5bd4STian Tao 		return ret;
102da52605eSRongrong Zou 
103770729f7STian Tao 	dev->mode_config.min_width = 0;
104770729f7STian Tao 	dev->mode_config.min_height = 0;
105770729f7STian Tao 	dev->mode_config.max_width = 1920;
106770729f7STian Tao 	dev->mode_config.max_height = 1200;
107da52605eSRongrong Zou 
108*53225f30SThomas Zimmermann 	dev->mode_config.preferred_depth = 24;
109770729f7STian Tao 	dev->mode_config.prefer_shadow = 1;
110da52605eSRongrong Zou 
111770729f7STian Tao 	dev->mode_config.funcs = (void *)&hibmc_mode_funcs;
112da52605eSRongrong Zou 
113da52605eSRongrong Zou 	ret = hibmc_de_init(priv);
114da52605eSRongrong Zou 	if (ret) {
115770729f7STian Tao 		drm_err(dev, "failed to init de: %d\n", ret);
116da52605eSRongrong Zou 		return ret;
117da52605eSRongrong Zou 	}
118da52605eSRongrong Zou 
1195294967fSRongrong Zou 	ret = hibmc_vdac_init(priv);
1205294967fSRongrong Zou 	if (ret) {
121770729f7STian Tao 		drm_err(dev, "failed to init vdac: %d\n", ret);
1225294967fSRongrong Zou 		return ret;
1235294967fSRongrong Zou 	}
1245294967fSRongrong Zou 
125da52605eSRongrong Zou 	return 0;
126da52605eSRongrong Zou }
127da52605eSRongrong Zou 
1285e0df3a0SRongrong Zou /*
1295e0df3a0SRongrong Zou  * It can operate in one of three modes: 0, 1 or Sleep.
1305e0df3a0SRongrong Zou  */
hibmc_set_power_mode(struct hibmc_drm_private * priv,u32 power_mode)1315fefd250STian Tao void hibmc_set_power_mode(struct hibmc_drm_private *priv, u32 power_mode)
1325e0df3a0SRongrong Zou {
1335fefd250STian Tao 	u32 control_value = 0;
1345e0df3a0SRongrong Zou 	void __iomem   *mmio = priv->mmio;
1355fefd250STian Tao 	u32 input = 1;
1365e0df3a0SRongrong Zou 
1375e0df3a0SRongrong Zou 	if (power_mode > HIBMC_PW_MODE_CTL_MODE_SLEEP)
1385e0df3a0SRongrong Zou 		return;
1395e0df3a0SRongrong Zou 
1405e0df3a0SRongrong Zou 	if (power_mode == HIBMC_PW_MODE_CTL_MODE_SLEEP)
1415e0df3a0SRongrong Zou 		input = 0;
1425e0df3a0SRongrong Zou 
1435e0df3a0SRongrong Zou 	control_value = readl(mmio + HIBMC_POWER_MODE_CTRL);
1445e0df3a0SRongrong Zou 	control_value &= ~(HIBMC_PW_MODE_CTL_MODE_MASK |
1455e0df3a0SRongrong Zou 			   HIBMC_PW_MODE_CTL_OSC_INPUT_MASK);
1465e0df3a0SRongrong Zou 	control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_MODE, power_mode);
1475e0df3a0SRongrong Zou 	control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_OSC_INPUT, input);
1485e0df3a0SRongrong Zou 	writel(control_value, mmio + HIBMC_POWER_MODE_CTRL);
1495e0df3a0SRongrong Zou }
1505e0df3a0SRongrong Zou 
hibmc_set_current_gate(struct hibmc_drm_private * priv,unsigned int gate)1515e0df3a0SRongrong Zou void hibmc_set_current_gate(struct hibmc_drm_private *priv, unsigned int gate)
1525e0df3a0SRongrong Zou {
1535fefd250STian Tao 	u32 gate_reg;
1545fefd250STian Tao 	u32 mode;
1555e0df3a0SRongrong Zou 	void __iomem   *mmio = priv->mmio;
1565e0df3a0SRongrong Zou 
1575e0df3a0SRongrong Zou 	/* Get current power mode. */
1585e0df3a0SRongrong Zou 	mode = (readl(mmio + HIBMC_POWER_MODE_CTRL) &
1595e0df3a0SRongrong Zou 		HIBMC_PW_MODE_CTL_MODE_MASK) >> HIBMC_PW_MODE_CTL_MODE_SHIFT;
1605e0df3a0SRongrong Zou 
1615e0df3a0SRongrong Zou 	switch (mode) {
1625e0df3a0SRongrong Zou 	case HIBMC_PW_MODE_CTL_MODE_MODE0:
1635e0df3a0SRongrong Zou 		gate_reg = HIBMC_MODE0_GATE;
1645e0df3a0SRongrong Zou 		break;
1655e0df3a0SRongrong Zou 
1665e0df3a0SRongrong Zou 	case HIBMC_PW_MODE_CTL_MODE_MODE1:
1675e0df3a0SRongrong Zou 		gate_reg = HIBMC_MODE1_GATE;
1685e0df3a0SRongrong Zou 		break;
1695e0df3a0SRongrong Zou 
1705e0df3a0SRongrong Zou 	default:
1715e0df3a0SRongrong Zou 		gate_reg = HIBMC_MODE0_GATE;
1725e0df3a0SRongrong Zou 		break;
1735e0df3a0SRongrong Zou 	}
1745e0df3a0SRongrong Zou 	writel(gate, mmio + gate_reg);
1755e0df3a0SRongrong Zou }
1765e0df3a0SRongrong Zou 
hibmc_hw_config(struct hibmc_drm_private * priv)1775e0df3a0SRongrong Zou static void hibmc_hw_config(struct hibmc_drm_private *priv)
1785e0df3a0SRongrong Zou {
1795fefd250STian Tao 	u32 reg;
1805e0df3a0SRongrong Zou 
1815e0df3a0SRongrong Zou 	/* On hardware reset, power mode 0 is default. */
1825e0df3a0SRongrong Zou 	hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
1835e0df3a0SRongrong Zou 
1845e0df3a0SRongrong Zou 	/* Enable display power gate & LOCALMEM power gate*/
1855e0df3a0SRongrong Zou 	reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
1865e0df3a0SRongrong Zou 	reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
1875e0df3a0SRongrong Zou 	reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
1885e0df3a0SRongrong Zou 	reg |= HIBMC_CURR_GATE_DISPLAY(1);
1895e0df3a0SRongrong Zou 	reg |= HIBMC_CURR_GATE_LOCALMEM(1);
1905e0df3a0SRongrong Zou 
1915e0df3a0SRongrong Zou 	hibmc_set_current_gate(priv, reg);
1925e0df3a0SRongrong Zou 
1935e0df3a0SRongrong Zou 	/*
1945e0df3a0SRongrong Zou 	 * Reset the memory controller. If the memory controller
1955e0df3a0SRongrong Zou 	 * is not reset in chip,the system might hang when sw accesses
1965e0df3a0SRongrong Zou 	 * the memory.The memory should be resetted after
1975e0df3a0SRongrong Zou 	 * changing the MXCLK.
1985e0df3a0SRongrong Zou 	 */
1995e0df3a0SRongrong Zou 	reg = readl(priv->mmio + HIBMC_MISC_CTRL);
2005e0df3a0SRongrong Zou 	reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
2015e0df3a0SRongrong Zou 	reg |= HIBMC_MSCCTL_LOCALMEM_RESET(0);
2025e0df3a0SRongrong Zou 	writel(reg, priv->mmio + HIBMC_MISC_CTRL);
2035e0df3a0SRongrong Zou 
2045e0df3a0SRongrong Zou 	reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
2055e0df3a0SRongrong Zou 	reg |= HIBMC_MSCCTL_LOCALMEM_RESET(1);
2065e0df3a0SRongrong Zou 
2075e0df3a0SRongrong Zou 	writel(reg, priv->mmio + HIBMC_MISC_CTRL);
2085e0df3a0SRongrong Zou }
2095e0df3a0SRongrong Zou 
hibmc_hw_map(struct hibmc_drm_private * priv)2105e0df3a0SRongrong Zou static int hibmc_hw_map(struct hibmc_drm_private *priv)
2115e0df3a0SRongrong Zou {
212657b6505STian Tao 	struct drm_device *dev = &priv->dev;
2134d4dad21SThomas Zimmermann 	struct pci_dev *pdev = to_pci_dev(dev->dev);
2147c99616eSZack Rusin 	resource_size_t ioaddr, iosize;
2155e0df3a0SRongrong Zou 
2165e0df3a0SRongrong Zou 	ioaddr = pci_resource_start(pdev, 1);
2175e0df3a0SRongrong Zou 	iosize = pci_resource_len(pdev, 1);
2184bdc0d67SChristoph Hellwig 	priv->mmio = devm_ioremap(dev->dev, ioaddr, iosize);
2195e0df3a0SRongrong Zou 	if (!priv->mmio) {
220389be500STian Tao 		drm_err(dev, "Cannot map mmio region\n");
2215e0df3a0SRongrong Zou 		return -ENOMEM;
2225e0df3a0SRongrong Zou 	}
2235e0df3a0SRongrong Zou 
2245e0df3a0SRongrong Zou 	return 0;
2255e0df3a0SRongrong Zou }
2265e0df3a0SRongrong Zou 
hibmc_hw_init(struct hibmc_drm_private * priv)2275e0df3a0SRongrong Zou static int hibmc_hw_init(struct hibmc_drm_private *priv)
2285e0df3a0SRongrong Zou {
2295e0df3a0SRongrong Zou 	int ret;
2305e0df3a0SRongrong Zou 
2315e0df3a0SRongrong Zou 	ret = hibmc_hw_map(priv);
2325e0df3a0SRongrong Zou 	if (ret)
2335e0df3a0SRongrong Zou 		return ret;
2345e0df3a0SRongrong Zou 
2355e0df3a0SRongrong Zou 	hibmc_hw_config(priv);
2365e0df3a0SRongrong Zou 
2375e0df3a0SRongrong Zou 	return 0;
2385e0df3a0SRongrong Zou }
2395e0df3a0SRongrong Zou 
hibmc_unload(struct drm_device * dev)2405e0df3a0SRongrong Zou static int hibmc_unload(struct drm_device *dev)
2415e0df3a0SRongrong Zou {
24239a364a1SThomas Zimmermann 	struct pci_dev *pdev = to_pci_dev(dev->dev);
24339a364a1SThomas Zimmermann 
244b3df5e65SDaniel Vetter 	drm_atomic_helper_shutdown(dev);
2459ede6f0aSTian Tao 
24639a364a1SThomas Zimmermann 	free_irq(pdev->irq, dev);
2479ede6f0aSTian Tao 
2484d4dad21SThomas Zimmermann 	pci_disable_msi(to_pci_dev(dev->dev));
2499a27d37aSTian Tao 
2505e0df3a0SRongrong Zou 	return 0;
2515e0df3a0SRongrong Zou }
2525e0df3a0SRongrong Zou 
hibmc_load(struct drm_device * dev)2535e0df3a0SRongrong Zou static int hibmc_load(struct drm_device *dev)
2545e0df3a0SRongrong Zou {
2554d4dad21SThomas Zimmermann 	struct pci_dev *pdev = to_pci_dev(dev->dev);
256770729f7STian Tao 	struct hibmc_drm_private *priv = to_hibmc_drm_private(dev);
2575e0df3a0SRongrong Zou 	int ret;
2585e0df3a0SRongrong Zou 
2595e0df3a0SRongrong Zou 	ret = hibmc_hw_init(priv);
2605e0df3a0SRongrong Zou 	if (ret)
2615e0df3a0SRongrong Zou 		goto err;
2625e0df3a0SRongrong Zou 
2637c99616eSZack Rusin 	ret = drmm_vram_helper_init(dev, pci_resource_start(pdev, 0),
2647c99616eSZack Rusin 				    pci_resource_len(pdev, 0));
265552a77baSTian Tao 	if (ret) {
266552a77baSTian Tao 		drm_err(dev, "Error initializing VRAM MM; %d\n", ret);
267e4daebc7SRongrong Zou 		goto err;
268552a77baSTian Tao 	}
269e4daebc7SRongrong Zou 
270da52605eSRongrong Zou 	ret = hibmc_kms_init(priv);
271da52605eSRongrong Zou 	if (ret)
272da52605eSRongrong Zou 		goto err;
273da52605eSRongrong Zou 
2741d98b916SRongrong Zou 	ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
2751d98b916SRongrong Zou 	if (ret) {
276389be500STian Tao 		drm_err(dev, "failed to initialize vblank: %d\n", ret);
2771d98b916SRongrong Zou 		goto err;
2781d98b916SRongrong Zou 	}
2791d98b916SRongrong Zou 
2804d4dad21SThomas Zimmermann 	ret = pci_enable_msi(pdev);
2811d98b916SRongrong Zou 	if (ret) {
282389be500STian Tao 		drm_warn(dev, "enabling MSI failed: %d\n", ret);
2831d98b916SRongrong Zou 	} else {
28439a364a1SThomas Zimmermann 		/* PCI devices require shared interrupts. */
28539a364a1SThomas Zimmermann 		ret = request_irq(pdev->irq, hibmc_interrupt, IRQF_SHARED,
28639a364a1SThomas Zimmermann 				  dev->driver->name, dev);
2871d98b916SRongrong Zou 		if (ret)
288389be500STian Tao 			drm_warn(dev, "install irq failed: %d\n", ret);
2891d98b916SRongrong Zou 	}
2901d98b916SRongrong Zou 
291da52605eSRongrong Zou 	/* reset all the states of crtc/plane/encoder/connector */
292da52605eSRongrong Zou 	drm_mode_config_reset(dev);
293da52605eSRongrong Zou 
2945e0df3a0SRongrong Zou 	return 0;
2955e0df3a0SRongrong Zou 
2965e0df3a0SRongrong Zou err:
2975e0df3a0SRongrong Zou 	hibmc_unload(dev);
298389be500STian Tao 	drm_err(dev, "failed to initialize drm driver: %d\n", ret);
2995e0df3a0SRongrong Zou 	return ret;
3005e0df3a0SRongrong Zou }
3015e0df3a0SRongrong Zou 
hibmc_pci_probe(struct pci_dev * pdev,const struct pci_device_id * ent)3025e0df3a0SRongrong Zou static int hibmc_pci_probe(struct pci_dev *pdev,
3035e0df3a0SRongrong Zou 			   const struct pci_device_id *ent)
3045e0df3a0SRongrong Zou {
305770729f7STian Tao 	struct hibmc_drm_private *priv;
3065e0df3a0SRongrong Zou 	struct drm_device *dev;
3075e0df3a0SRongrong Zou 	int ret;
3085e0df3a0SRongrong Zou 
30997c9bfe3SThomas Zimmermann 	ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &hibmc_driver);
310c3480301STian Tao 	if (ret)
311c3480301STian Tao 		return ret;
312c3480301STian Tao 
313770729f7STian Tao 	priv = devm_drm_dev_alloc(&pdev->dev, &hibmc_driver,
314770729f7STian Tao 				  struct hibmc_drm_private, dev);
315770729f7STian Tao 	if (IS_ERR(priv)) {
3165e0df3a0SRongrong Zou 		DRM_ERROR("failed to allocate drm_device\n");
317770729f7STian Tao 		return PTR_ERR(priv);
3185e0df3a0SRongrong Zou 	}
3195e0df3a0SRongrong Zou 
320770729f7STian Tao 	dev = &priv->dev;
3215e0df3a0SRongrong Zou 	pci_set_drvdata(pdev, dev);
3225e0df3a0SRongrong Zou 
3234c5d02d9STian Tao 	ret = pcim_enable_device(pdev);
3245e0df3a0SRongrong Zou 	if (ret) {
325389be500STian Tao 		drm_err(dev, "failed to enable pci device: %d\n", ret);
32672eab0baSTian Tao 		goto err_return;
3275e0df3a0SRongrong Zou 	}
3285e0df3a0SRongrong Zou 
3295e0df3a0SRongrong Zou 	ret = hibmc_load(dev);
3305e0df3a0SRongrong Zou 	if (ret) {
331389be500STian Tao 		drm_err(dev, "failed to load hibmc: %d\n", ret);
33272eab0baSTian Tao 		goto err_return;
3335e0df3a0SRongrong Zou 	}
3345e0df3a0SRongrong Zou 
3355e0df3a0SRongrong Zou 	ret = drm_dev_register(dev, 0);
3365e0df3a0SRongrong Zou 	if (ret) {
337389be500STian Tao 		drm_err(dev, "failed to register drv for userspace access: %d\n",
3385e0df3a0SRongrong Zou 			  ret);
3395e0df3a0SRongrong Zou 		goto err_unload;
3405e0df3a0SRongrong Zou 	}
34100debf81SZenghui Yu 
342*53225f30SThomas Zimmermann 	drm_fbdev_generic_setup(dev, 32);
34300debf81SZenghui Yu 
3445e0df3a0SRongrong Zou 	return 0;
3455e0df3a0SRongrong Zou 
3465e0df3a0SRongrong Zou err_unload:
3475e0df3a0SRongrong Zou 	hibmc_unload(dev);
34872eab0baSTian Tao err_return:
3495e0df3a0SRongrong Zou 	return ret;
3505e0df3a0SRongrong Zou }
3515e0df3a0SRongrong Zou 
hibmc_pci_remove(struct pci_dev * pdev)3525e0df3a0SRongrong Zou static void hibmc_pci_remove(struct pci_dev *pdev)
3535e0df3a0SRongrong Zou {
3545e0df3a0SRongrong Zou 	struct drm_device *dev = pci_get_drvdata(pdev);
3555e0df3a0SRongrong Zou 
3565e0df3a0SRongrong Zou 	drm_dev_unregister(dev);
3575e0df3a0SRongrong Zou 	hibmc_unload(dev);
3585e0df3a0SRongrong Zou }
3595e0df3a0SRongrong Zou 
360dbc8c28aSTian Tao static const struct pci_device_id hibmc_pci_table[] = {
361a66dae3aSJohn Garry 	{ PCI_VDEVICE(HUAWEI, 0x1711) },
3625e0df3a0SRongrong Zou 	{0,}
3635e0df3a0SRongrong Zou };
3645e0df3a0SRongrong Zou 
3655e0df3a0SRongrong Zou static struct pci_driver hibmc_pci_driver = {
3665e0df3a0SRongrong Zou 	.name =		"hibmc-drm",
3675e0df3a0SRongrong Zou 	.id_table =	hibmc_pci_table,
3685e0df3a0SRongrong Zou 	.probe =	hibmc_pci_probe,
3695e0df3a0SRongrong Zou 	.remove =	hibmc_pci_remove,
3705e0df3a0SRongrong Zou 	.driver.pm =    &hibmc_pm_ops,
3715e0df3a0SRongrong Zou };
3725e0df3a0SRongrong Zou 
3732075a734SThomas Zimmermann drm_module_pci_driver(hibmc_pci_driver);
3745e0df3a0SRongrong Zou 
3755e0df3a0SRongrong Zou MODULE_DEVICE_TABLE(pci, hibmc_pci_table);
3765e0df3a0SRongrong Zou MODULE_AUTHOR("RongrongZou <zourongrong@huawei.com>");
3775e0df3a0SRongrong Zou MODULE_DESCRIPTION("DRM Driver for Hisilicon Hibmc");
3785e0df3a0SRongrong Zou MODULE_LICENSE("GPL v2");
379