1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * linux/drivers/video/mmp/common.c
4 * This driver is a common framework for Marvell Display Controller
6 * Copyright (C) 2012 Marvell Technology Group Ltd.
7 * Authors: Zhou Zhu <zzhu3@marvell.com>
10 #include <linux/slab.h>
11 #include <linux/dma-mapping.h>
12 #include <linux/export.h>
13 #include <linux/module.h>
14 #include <video/mmp_disp.h>
16 static struct mmp_overlay
*path_get_overlay(struct mmp_path
*path
,
19 if (path
&& overlay_id
< path
->overlay_num
)
20 return &path
->overlays
[overlay_id
];
24 static int path_check_status(struct mmp_path
*path
)
27 for (i
= 0; i
< path
->overlay_num
; i
++)
28 if (path
->overlays
[i
].status
)
35 * Get modelist write pointer of modelist.
36 * It also returns modelist number
37 * this function fetches modelist from phy/panel:
38 * for HDMI/parallel or dsi to hdmi cases, get from phy
41 static int path_get_modelist(struct mmp_path
*path
,
42 struct mmp_mode
**modelist
)
44 BUG_ON(!path
|| !modelist
);
46 if (path
->panel
&& path
->panel
->get_modelist
)
47 return path
->panel
->get_modelist(path
->panel
, modelist
);
53 * panel list is used to pair panel/path when path/panel registered
54 * path list is used for both buffer driver and platdriver
55 * plat driver do path register/unregister
56 * panel driver do panel register/unregister
57 * buffer driver get registered path
59 static LIST_HEAD(panel_list
);
60 static LIST_HEAD(path_list
);
61 static DEFINE_MUTEX(disp_lock
);
64 * mmp_register_panel - register panel to panel_list and connect to path
65 * @p: panel to be registered
67 * this function provides interface for panel drivers to register panel
68 * to panel_list and connect to path which matchs panel->plat_path_name.
69 * no error returns when no matching path is found as path register after
70 * panel register is permitted.
72 void mmp_register_panel(struct mmp_panel
*panel
)
74 struct mmp_path
*path
;
76 mutex_lock(&disp_lock
);
79 list_add_tail(&panel
->node
, &panel_list
);
81 /* try to register to path */
82 list_for_each_entry(path
, &path_list
, node
) {
83 if (!strcmp(panel
->plat_path_name
, path
->name
)) {
84 dev_info(panel
->dev
, "connect to path %s\n",
91 mutex_unlock(&disp_lock
);
93 EXPORT_SYMBOL_GPL(mmp_register_panel
);
96 * mmp_unregister_panel - unregister panel from panel_list and disconnect
97 * @p: panel to be unregistered
99 * this function provides interface for panel drivers to unregister panel
100 * from panel_list and disconnect from path.
102 void mmp_unregister_panel(struct mmp_panel
*panel
)
104 struct mmp_path
*path
;
106 mutex_lock(&disp_lock
);
107 list_del(&panel
->node
);
109 list_for_each_entry(path
, &path_list
, node
) {
110 if (path
->panel
&& path
->panel
== panel
) {
111 dev_info(panel
->dev
, "disconnect from path %s\n",
117 mutex_unlock(&disp_lock
);
119 EXPORT_SYMBOL_GPL(mmp_unregister_panel
);
122 * mmp_get_path - get path by name
125 * this function checks path name in path_list and return matching path
126 * return NULL if no matching path
128 struct mmp_path
*mmp_get_path(const char *name
)
130 struct mmp_path
*path
;
133 mutex_lock(&disp_lock
);
134 list_for_each_entry(path
, &path_list
, node
) {
135 if (!strcmp(name
, path
->name
)) {
140 mutex_unlock(&disp_lock
);
142 return found
? path
: NULL
;
144 EXPORT_SYMBOL_GPL(mmp_get_path
);
147 * mmp_register_path - init and register path by path_info
148 * @p: path info provided by display controller
150 * this function init by path info and register path to path_list
151 * this function also try to connect path with panel by name
153 struct mmp_path
*mmp_register_path(struct mmp_path_info
*info
)
156 struct mmp_path
*path
= NULL
;
157 struct mmp_panel
*panel
;
159 path
= kzalloc(struct_size(path
, overlays
, info
->overlay_num
),
165 mutex_init(&path
->access_ok
);
166 path
->dev
= info
->dev
;
168 path
->name
= info
->name
;
169 path
->output_type
= info
->output_type
;
170 path
->overlay_num
= info
->overlay_num
;
171 path
->plat_data
= info
->plat_data
;
172 path
->ops
.set_mode
= info
->set_mode
;
174 mutex_lock(&disp_lock
);
176 list_for_each_entry(panel
, &panel_list
, node
) {
177 if (!strcmp(info
->name
, panel
->plat_path_name
)) {
178 dev_info(path
->dev
, "get panel %s\n", panel
->name
);
184 dev_info(path
->dev
, "register %s, overlay_num %d\n",
185 path
->name
, path
->overlay_num
);
187 /* default op set: if already set by driver, never cover it */
188 if (!path
->ops
.check_status
)
189 path
->ops
.check_status
= path_check_status
;
190 if (!path
->ops
.get_overlay
)
191 path
->ops
.get_overlay
= path_get_overlay
;
192 if (!path
->ops
.get_modelist
)
193 path
->ops
.get_modelist
= path_get_modelist
;
195 /* step3: init overlays */
196 for (i
= 0; i
< path
->overlay_num
; i
++) {
197 path
->overlays
[i
].path
= path
;
198 path
->overlays
[i
].id
= i
;
199 mutex_init(&path
->overlays
[i
].access_ok
);
200 path
->overlays
[i
].ops
= info
->overlay_ops
;
203 /* add to pathlist */
204 list_add_tail(&path
->node
, &path_list
);
206 mutex_unlock(&disp_lock
);
209 EXPORT_SYMBOL_GPL(mmp_register_path
);
212 * mmp_unregister_path - unregister and destroy path
213 * @p: path to be destroyed.
215 * this function registers path and destroys it.
217 void mmp_unregister_path(struct mmp_path
*path
)
224 mutex_lock(&disp_lock
);
225 /* del from pathlist */
226 list_del(&path
->node
);
228 /* deinit overlays */
229 for (i
= 0; i
< path
->overlay_num
; i
++)
230 mutex_destroy(&path
->overlays
[i
].access_ok
);
232 mutex_destroy(&path
->access_ok
);
235 mutex_unlock(&disp_lock
);
237 EXPORT_SYMBOL_GPL(mmp_unregister_path
);
239 MODULE_AUTHOR("Zhou Zhu <zzhu3@marvell.com>");
240 MODULE_DESCRIPTION("Marvell MMP display framework");
241 MODULE_LICENSE("GPL");