Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
shmob_drm_drv.c
Go to the documentation of this file.
1 /*
2  * shmob_drm_drv.c -- SH Mobile DRM driver
3  *
4  * Copyright (C) 2012 Renesas Corporation
5  *
6  * Laurent Pinchart ([email protected])
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  */
13 
14 #include <linux/clk.h>
15 #include <linux/io.h>
16 #include <linux/mm.h>
17 #include <linux/module.h>
18 #include <linux/platform_device.h>
19 #include <linux/pm.h>
20 #include <linux/slab.h>
21 
22 #include <drm/drmP.h>
23 #include <drm/drm_crtc_helper.h>
24 #include <drm/drm_gem_cma_helper.h>
25 
26 #include "shmob_drm_crtc.h"
27 #include "shmob_drm_drv.h"
28 #include "shmob_drm_kms.h"
29 #include "shmob_drm_plane.h"
30 #include "shmob_drm_regs.h"
31 
32 /* -----------------------------------------------------------------------------
33  * Hardware initialization
34  */
35 
36 static int __devinit shmob_drm_init_interface(struct shmob_drm_device *sdev)
37 {
38  static const u32 ldmt1r[] = {
58  };
59 
60  if (sdev->pdata->iface.interface >= ARRAY_SIZE(ldmt1r)) {
61  dev_err(sdev->dev, "invalid interface type %u\n",
62  sdev->pdata->iface.interface);
63  return -EINVAL;
64  }
65 
66  sdev->ldmt1r = ldmt1r[sdev->pdata->iface.interface];
67  return 0;
68 }
69 
70 static int __devinit shmob_drm_setup_clocks(struct shmob_drm_device *sdev,
71  enum shmob_drm_clk_source clksrc)
72 {
73  struct clk *clk;
74  char *clkname;
75 
76  switch (clksrc) {
77  case SHMOB_DRM_CLK_BUS:
78  clkname = "bus_clk";
79  sdev->lddckr = LDDCKR_ICKSEL_BUS;
80  break;
82  clkname = "peripheral_clk";
83  sdev->lddckr = LDDCKR_ICKSEL_MIPI;
84  break;
86  clkname = NULL;
87  sdev->lddckr = LDDCKR_ICKSEL_HDMI;
88  break;
89  default:
90  return -EINVAL;
91  }
92 
93  clk = clk_get(sdev->dev, clkname);
94  if (IS_ERR(clk)) {
95  dev_err(sdev->dev, "cannot get dot clock %s\n", clkname);
96  return PTR_ERR(clk);
97  }
98 
99  sdev->clock = clk;
100  return 0;
101 }
102 
103 /* -----------------------------------------------------------------------------
104  * DRM operations
105  */
106 
107 static int shmob_drm_unload(struct drm_device *dev)
108 {
109  struct shmob_drm_device *sdev = dev->dev_private;
110 
113  drm_vblank_cleanup(dev);
114  drm_irq_uninstall(dev);
115 
116  if (sdev->clock)
117  clk_put(sdev->clock);
118 
119  if (sdev->mmio)
120  iounmap(sdev->mmio);
121 
122  dev->dev_private = NULL;
123  kfree(sdev);
124 
125  return 0;
126 }
127 
128 static int shmob_drm_load(struct drm_device *dev, unsigned long flags)
129 {
130  struct shmob_drm_platform_data *pdata = dev->dev->platform_data;
131  struct platform_device *pdev = dev->platformdev;
132  struct shmob_drm_device *sdev;
133  struct resource *res;
134  unsigned int i;
135  int ret;
136 
137  if (pdata == NULL) {
138  dev_err(dev->dev, "no platform data\n");
139  return -EINVAL;
140  }
141 
142  sdev = kzalloc(sizeof(*sdev), GFP_KERNEL);
143  if (sdev == NULL) {
144  dev_err(dev->dev, "failed to allocate private data\n");
145  return -ENOMEM;
146  }
147 
148  sdev->dev = &pdev->dev;
149  sdev->pdata = pdata;
150  spin_lock_init(&sdev->irq_lock);
151 
152  sdev->ddev = dev;
153  dev->dev_private = sdev;
154 
155  /* I/O resources and clocks */
156  res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
157  if (res == NULL) {
158  dev_err(&pdev->dev, "failed to get memory resource\n");
159  ret = -EINVAL;
160  goto done;
161  }
162 
163  sdev->mmio = ioremap_nocache(res->start, resource_size(res));
164  if (sdev->mmio == NULL) {
165  dev_err(&pdev->dev, "failed to remap memory resource\n");
166  ret = -ENOMEM;
167  goto done;
168  }
169 
170  ret = shmob_drm_setup_clocks(sdev, pdata->clk_source);
171  if (ret < 0)
172  goto done;
173 
174  ret = shmob_drm_init_interface(sdev);
175  if (ret < 0)
176  goto done;
177 
178  ret = shmob_drm_modeset_init(sdev);
179  if (ret < 0) {
180  dev_err(&pdev->dev, "failed to initialize mode setting\n");
181  goto done;
182  }
183 
184  for (i = 0; i < 4; ++i) {
185  ret = shmob_drm_plane_create(sdev, i);
186  if (ret < 0) {
187  dev_err(&pdev->dev, "failed to create plane %u\n", i);
188  goto done;
189  }
190  }
191 
192  ret = drm_vblank_init(dev, 1);
193  if (ret < 0) {
194  dev_err(&pdev->dev, "failed to initialize vblank\n");
195  goto done;
196  }
197 
198  ret = drm_irq_install(dev);
199  if (ret < 0) {
200  dev_err(&pdev->dev, "failed to install IRQ handler\n");
201  goto done;
202  }
203 
204  platform_set_drvdata(pdev, sdev);
205 
206 done:
207  if (ret)
208  shmob_drm_unload(dev);
209 
210  return ret;
211 }
212 
213 static void shmob_drm_preclose(struct drm_device *dev, struct drm_file *file)
214 {
215  struct shmob_drm_device *sdev = dev->dev_private;
216 
218 }
219 
220 static irqreturn_t shmob_drm_irq(int irq, void *arg)
221 {
222  struct drm_device *dev = arg;
223  struct shmob_drm_device *sdev = dev->dev_private;
224  unsigned long flags;
225  u32 status;
226 
227  /* Acknowledge interrupts. Putting interrupt enable and interrupt flag
228  * bits in the same register is really brain-dead design and requires
229  * taking a spinlock.
230  */
231  spin_lock_irqsave(&sdev->irq_lock, flags);
232  status = lcdc_read(sdev, LDINTR);
233  lcdc_write(sdev, LDINTR, status ^ LDINTR_STATUS_MASK);
234  spin_unlock_irqrestore(&sdev->irq_lock, flags);
235 
236  if (status & LDINTR_VES) {
237  drm_handle_vblank(dev, 0);
239  }
240 
241  return IRQ_HANDLED;
242 }
243 
244 static int shmob_drm_enable_vblank(struct drm_device *dev, int crtc)
245 {
246  struct shmob_drm_device *sdev = dev->dev_private;
247 
248  shmob_drm_crtc_enable_vblank(sdev, true);
249 
250  return 0;
251 }
252 
253 static void shmob_drm_disable_vblank(struct drm_device *dev, int crtc)
254 {
255  struct shmob_drm_device *sdev = dev->dev_private;
256 
257  shmob_drm_crtc_enable_vblank(sdev, false);
258 }
259 
260 static const struct file_operations shmob_drm_fops = {
261  .owner = THIS_MODULE,
262  .open = drm_open,
263  .release = drm_release,
264  .unlocked_ioctl = drm_ioctl,
265 #ifdef CONFIG_COMPAT
266  .compat_ioctl = drm_compat_ioctl,
267 #endif
268  .poll = drm_poll,
269  .read = drm_read,
270  .fasync = drm_fasync,
271  .llseek = no_llseek,
272  .mmap = drm_gem_cma_mmap,
273 };
274 
275 static struct drm_driver shmob_drm_driver = {
276  .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET,
277  .load = shmob_drm_load,
278  .unload = shmob_drm_unload,
279  .preclose = shmob_drm_preclose,
280  .irq_handler = shmob_drm_irq,
281  .get_vblank_counter = drm_vblank_count,
282  .enable_vblank = shmob_drm_enable_vblank,
283  .disable_vblank = shmob_drm_disable_vblank,
284  .gem_free_object = drm_gem_cma_free_object,
285  .gem_vm_ops = &drm_gem_cma_vm_ops,
286  .dumb_create = drm_gem_cma_dumb_create,
287  .dumb_map_offset = drm_gem_cma_dumb_map_offset,
288  .dumb_destroy = drm_gem_cma_dumb_destroy,
289  .fops = &shmob_drm_fops,
290  .name = "shmob-drm",
291  .desc = "Renesas SH Mobile DRM",
292  .date = "20120424",
293  .major = 1,
294  .minor = 0,
295 };
296 
297 /* -----------------------------------------------------------------------------
298  * Power management
299  */
300 
301 #if CONFIG_PM_SLEEP
302 static int shmob_drm_pm_suspend(struct device *dev)
303 {
304  struct shmob_drm_device *sdev = dev_get_drvdata(dev);
305 
308 
309  return 0;
310 }
311 
312 static int shmob_drm_pm_resume(struct device *dev)
313 {
314  struct shmob_drm_device *sdev = dev_get_drvdata(dev);
315 
316  mutex_lock(&sdev->ddev->mode_config.mutex);
317  shmob_drm_crtc_resume(&sdev->crtc);
318  mutex_unlock(&sdev->ddev->mode_config.mutex);
319 
321  return 0;
322 }
323 #endif
324 
325 static const struct dev_pm_ops shmob_drm_pm_ops = {
326  SET_SYSTEM_SLEEP_PM_OPS(shmob_drm_pm_suspend, shmob_drm_pm_resume)
327 };
328 
329 /* -----------------------------------------------------------------------------
330  * Platform driver
331  */
332 
333 static int __devinit shmob_drm_probe(struct platform_device *pdev)
334 {
335  return drm_platform_init(&shmob_drm_driver, pdev);
336 }
337 
338 static int __devexit shmob_drm_remove(struct platform_device *pdev)
339 {
340  drm_platform_exit(&shmob_drm_driver, pdev);
341 
342  return 0;
343 }
344 
345 static struct platform_driver shmob_drm_platform_driver = {
346  .probe = shmob_drm_probe,
347  .remove = __devexit_p(shmob_drm_remove),
348  .driver = {
349  .owner = THIS_MODULE,
350  .name = "shmob-drm",
351  .pm = &shmob_drm_pm_ops,
352  },
353 };
354 
355 module_platform_driver(shmob_drm_platform_driver);
356 
357 MODULE_AUTHOR("Laurent Pinchart <[email protected]>");
358 MODULE_DESCRIPTION("Renesas SH Mobile DRM Driver");
359 MODULE_LICENSE("GPL");