]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
drm/hisilicon/hibmc: Add video memory management
[mirror_ubuntu-bionic-kernel.git] / drivers / gpu / drm / hisilicon / hibmc / hibmc_drm_drv.c
CommitLineData
5e0df3a0
RZ
1/* Hisilicon Hibmc SoC drm driver
2 *
3 * Based on the bochs drm driver.
4 *
5 * Copyright (c) 2016 Huawei Limited.
6 *
7 * Author:
8 * Rongrong Zou <zourongrong@huawei.com>
9 * Rongrong Zou <zourongrong@gmail.com>
10 * Jianhua Li <lijianhua@huawei.com>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 */
18
19#include <linux/console.h>
20#include <linux/module.h>
21
22#include "hibmc_drm_drv.h"
23#include "hibmc_drm_regs.h"
24
25static const struct file_operations hibmc_fops = {
26 .owner = THIS_MODULE,
27 .open = drm_open,
28 .release = drm_release,
29 .unlocked_ioctl = drm_ioctl,
30 .compat_ioctl = drm_compat_ioctl,
e4daebc7 31 .mmap = hibmc_mmap,
5e0df3a0
RZ
32 .poll = drm_poll,
33 .read = drm_read,
34 .llseek = no_llseek,
35};
36
37static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
38{
39 return 0;
40}
41
42static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
43{
44}
45
46static struct drm_driver hibmc_driver = {
e4daebc7 47 .driver_features = DRIVER_GEM,
5e0df3a0
RZ
48 .fops = &hibmc_fops,
49 .name = "hibmc",
50 .date = "20160828",
51 .desc = "hibmc drm driver",
52 .major = 1,
53 .minor = 0,
54 .get_vblank_counter = drm_vblank_no_hw_counter,
55 .enable_vblank = hibmc_enable_vblank,
56 .disable_vblank = hibmc_disable_vblank,
e4daebc7
RZ
57 .gem_free_object_unlocked = hibmc_gem_free_object,
58 .dumb_create = hibmc_dumb_create,
59 .dumb_map_offset = hibmc_dumb_mmap_offset,
60 .dumb_destroy = drm_gem_dumb_destroy,
5e0df3a0
RZ
61};
62
63static int hibmc_pm_suspend(struct device *dev)
64{
65 return 0;
66}
67
68static int hibmc_pm_resume(struct device *dev)
69{
70 return 0;
71}
72
73static const struct dev_pm_ops hibmc_pm_ops = {
74 SET_SYSTEM_SLEEP_PM_OPS(hibmc_pm_suspend,
75 hibmc_pm_resume)
76};
77
78/*
79 * It can operate in one of three modes: 0, 1 or Sleep.
80 */
81void hibmc_set_power_mode(struct hibmc_drm_private *priv,
82 unsigned int power_mode)
83{
84 unsigned int control_value = 0;
85 void __iomem *mmio = priv->mmio;
86 unsigned int input = 1;
87
88 if (power_mode > HIBMC_PW_MODE_CTL_MODE_SLEEP)
89 return;
90
91 if (power_mode == HIBMC_PW_MODE_CTL_MODE_SLEEP)
92 input = 0;
93
94 control_value = readl(mmio + HIBMC_POWER_MODE_CTRL);
95 control_value &= ~(HIBMC_PW_MODE_CTL_MODE_MASK |
96 HIBMC_PW_MODE_CTL_OSC_INPUT_MASK);
97 control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_MODE, power_mode);
98 control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_OSC_INPUT, input);
99 writel(control_value, mmio + HIBMC_POWER_MODE_CTRL);
100}
101
102void hibmc_set_current_gate(struct hibmc_drm_private *priv, unsigned int gate)
103{
104 unsigned int gate_reg;
105 unsigned int mode;
106 void __iomem *mmio = priv->mmio;
107
108 /* Get current power mode. */
109 mode = (readl(mmio + HIBMC_POWER_MODE_CTRL) &
110 HIBMC_PW_MODE_CTL_MODE_MASK) >> HIBMC_PW_MODE_CTL_MODE_SHIFT;
111
112 switch (mode) {
113 case HIBMC_PW_MODE_CTL_MODE_MODE0:
114 gate_reg = HIBMC_MODE0_GATE;
115 break;
116
117 case HIBMC_PW_MODE_CTL_MODE_MODE1:
118 gate_reg = HIBMC_MODE1_GATE;
119 break;
120
121 default:
122 gate_reg = HIBMC_MODE0_GATE;
123 break;
124 }
125 writel(gate, mmio + gate_reg);
126}
127
128static void hibmc_hw_config(struct hibmc_drm_private *priv)
129{
130 unsigned int reg;
131
132 /* On hardware reset, power mode 0 is default. */
133 hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
134
135 /* Enable display power gate & LOCALMEM power gate*/
136 reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
137 reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
138 reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
139 reg |= HIBMC_CURR_GATE_DISPLAY(1);
140 reg |= HIBMC_CURR_GATE_LOCALMEM(1);
141
142 hibmc_set_current_gate(priv, reg);
143
144 /*
145 * Reset the memory controller. If the memory controller
146 * is not reset in chip,the system might hang when sw accesses
147 * the memory.The memory should be resetted after
148 * changing the MXCLK.
149 */
150 reg = readl(priv->mmio + HIBMC_MISC_CTRL);
151 reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
152 reg |= HIBMC_MSCCTL_LOCALMEM_RESET(0);
153 writel(reg, priv->mmio + HIBMC_MISC_CTRL);
154
155 reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
156 reg |= HIBMC_MSCCTL_LOCALMEM_RESET(1);
157
158 writel(reg, priv->mmio + HIBMC_MISC_CTRL);
159}
160
161static int hibmc_hw_map(struct hibmc_drm_private *priv)
162{
163 struct drm_device *dev = priv->dev;
164 struct pci_dev *pdev = dev->pdev;
165 resource_size_t addr, size, ioaddr, iosize;
166
167 ioaddr = pci_resource_start(pdev, 1);
168 iosize = pci_resource_len(pdev, 1);
169 priv->mmio = devm_ioremap_nocache(dev->dev, ioaddr, iosize);
170 if (!priv->mmio) {
171 DRM_ERROR("Cannot map mmio region\n");
172 return -ENOMEM;
173 }
174
175 addr = pci_resource_start(pdev, 0);
176 size = pci_resource_len(pdev, 0);
177 priv->fb_map = devm_ioremap(dev->dev, addr, size);
178 if (!priv->fb_map) {
179 DRM_ERROR("Cannot map framebuffer\n");
180 return -ENOMEM;
181 }
182 priv->fb_base = addr;
183 priv->fb_size = size;
184
185 return 0;
186}
187
188static int hibmc_hw_init(struct hibmc_drm_private *priv)
189{
190 int ret;
191
192 ret = hibmc_hw_map(priv);
193 if (ret)
194 return ret;
195
196 hibmc_hw_config(priv);
197
198 return 0;
199}
200
201static int hibmc_unload(struct drm_device *dev)
202{
e4daebc7
RZ
203 struct hibmc_drm_private *priv = dev->dev_private;
204
205 hibmc_mm_fini(priv);
206 dev->dev_private = NULL;
5e0df3a0
RZ
207 return 0;
208}
209
210static int hibmc_load(struct drm_device *dev)
211{
212 struct hibmc_drm_private *priv;
213 int ret;
214
215 priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
216 if (!priv) {
217 DRM_ERROR("no memory to allocate for hibmc_drm_private\n");
218 return -ENOMEM;
219 }
220 dev->dev_private = priv;
221 priv->dev = dev;
222
223 ret = hibmc_hw_init(priv);
224 if (ret)
225 goto err;
226
e4daebc7
RZ
227 ret = hibmc_mm_init(priv);
228 if (ret)
229 goto err;
230
5e0df3a0
RZ
231 return 0;
232
233err:
234 hibmc_unload(dev);
235 DRM_ERROR("failed to initialize drm driver: %d\n", ret);
236 return ret;
237}
238
239static int hibmc_pci_probe(struct pci_dev *pdev,
240 const struct pci_device_id *ent)
241{
242 struct drm_device *dev;
243 int ret;
244
245 dev = drm_dev_alloc(&hibmc_driver, &pdev->dev);
246 if (!dev) {
247 DRM_ERROR("failed to allocate drm_device\n");
248 return -ENOMEM;
249 }
250
251 dev->pdev = pdev;
252 pci_set_drvdata(pdev, dev);
253
254 ret = pci_enable_device(pdev);
255 if (ret) {
256 DRM_ERROR("failed to enable pci device: %d\n", ret);
257 goto err_free;
258 }
259
260 ret = hibmc_load(dev);
261 if (ret) {
262 DRM_ERROR("failed to load hibmc: %d\n", ret);
263 goto err_disable;
264 }
265
266 ret = drm_dev_register(dev, 0);
267 if (ret) {
268 DRM_ERROR("failed to register drv for userspace access: %d\n",
269 ret);
270 goto err_unload;
271 }
272 return 0;
273
274err_unload:
275 hibmc_unload(dev);
276err_disable:
277 pci_disable_device(pdev);
278err_free:
279 drm_dev_unref(dev);
280
281 return ret;
282}
283
284static void hibmc_pci_remove(struct pci_dev *pdev)
285{
286 struct drm_device *dev = pci_get_drvdata(pdev);
287
288 drm_dev_unregister(dev);
289 hibmc_unload(dev);
290 drm_dev_unref(dev);
291}
292
293static struct pci_device_id hibmc_pci_table[] = {
294 {0x19e5, 0x1711, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
295 {0,}
296};
297
298static struct pci_driver hibmc_pci_driver = {
299 .name = "hibmc-drm",
300 .id_table = hibmc_pci_table,
301 .probe = hibmc_pci_probe,
302 .remove = hibmc_pci_remove,
303 .driver.pm = &hibmc_pm_ops,
304};
305
306static int __init hibmc_init(void)
307{
308 return pci_register_driver(&hibmc_pci_driver);
309}
310
311static void __exit hibmc_exit(void)
312{
313 return pci_unregister_driver(&hibmc_pci_driver);
314}
315
316module_init(hibmc_init);
317module_exit(hibmc_exit);
318
319MODULE_DEVICE_TABLE(pci, hibmc_pci_table);
320MODULE_AUTHOR("RongrongZou <zourongrong@huawei.com>");
321MODULE_DESCRIPTION("DRM Driver for Hisilicon Hibmc");
322MODULE_LICENSE("GPL v2");