1/* exynos_drm_core.c
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * Author:
5 *	Inki Dae <inki.dae@samsung.com>
6 *	Joonyoung Shim <jy0922.shim@samsung.com>
7 *	Seung-Woo Kim <sw0312.kim@samsung.com>
8 *
9 * This program is free software; you can redistribute  it and/or modify it
10 * under  the terms of  the GNU General  Public License as published by the
11 * Free Software Foundation;  either version 2 of the  License, or (at your
12 * option) any later version.
13 */
14
15#include <drm/drmP.h>
16#include "exynos_drm_drv.h"
17#include "exynos_drm_crtc.h"
18#include "exynos_drm_fbdev.h"
19
20static LIST_HEAD(exynos_drm_subdrv_list);
21
22int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
23{
24	if (!subdrv)
25		return -EINVAL;
26
27	list_add_tail(&subdrv->list, &exynos_drm_subdrv_list);
28
29	return 0;
30}
31
32int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
33{
34	if (!subdrv)
35		return -EINVAL;
36
37	list_del(&subdrv->list);
38
39	return 0;
40}
41
42int exynos_drm_device_subdrv_probe(struct drm_device *dev)
43{
44	struct exynos_drm_subdrv *subdrv, *n;
45	int err;
46
47	if (!dev)
48		return -EINVAL;
49
50	list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) {
51		if (subdrv->probe) {
52			subdrv->drm_dev = dev;
53
54			/*
55			 * this probe callback would be called by sub driver
56			 * after setting of all resources to this sub driver,
57			 * such as clock, irq and register map are done.
58			 */
59			err = subdrv->probe(dev, subdrv->dev);
60			if (err) {
61				DRM_DEBUG("exynos drm subdrv probe failed.\n");
62				list_del(&subdrv->list);
63				continue;
64			}
65		}
66	}
67
68	return 0;
69}
70
71int exynos_drm_device_subdrv_remove(struct drm_device *dev)
72{
73	struct exynos_drm_subdrv *subdrv;
74
75	if (!dev) {
76		WARN(1, "Unexpected drm device unregister!\n");
77		return -EINVAL;
78	}
79
80	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
81		if (subdrv->remove)
82			subdrv->remove(dev, subdrv->dev);
83	}
84
85	return 0;
86}
87
88int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file)
89{
90	struct exynos_drm_subdrv *subdrv;
91	int ret;
92
93	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
94		if (subdrv->open) {
95			ret = subdrv->open(dev, subdrv->dev, file);
96			if (ret)
97				goto err;
98		}
99	}
100
101	return 0;
102
103err:
104	list_for_each_entry_reverse(subdrv, &subdrv->list, list) {
105		if (subdrv->close)
106			subdrv->close(dev, subdrv->dev, file);
107	}
108	return ret;
109}
110
111void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file)
112{
113	struct exynos_drm_subdrv *subdrv;
114
115	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
116		if (subdrv->close)
117			subdrv->close(dev, subdrv->dev, file);
118	}
119}
120