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
= NULL
, *iter
;
132 mutex_lock(&disp_lock
);
133 list_for_each_entry(iter
, &path_list
, node
) {
134 if (!strcmp(name
, iter
->name
)) {
139 mutex_unlock(&disp_lock
);
143 EXPORT_SYMBOL_GPL(mmp_get_path
);
146 * mmp_register_path - init and register path by path_info
147 * @p: path info provided by display controller
149 * this function init by path info and register path to path_list
150 * this function also try to connect path with panel by name
152 struct mmp_path
*mmp_register_path(struct mmp_path_info
*info
)
155 struct mmp_path
*path
= NULL
;
156 struct mmp_panel
*panel
;
158 path
= kzalloc(struct_size(path
, overlays
, info
->overlay_num
),
164 mutex_init(&path
->access_ok
);
165 path
->dev
= info
->dev
;
167 path
->name
= info
->name
;
168 path
->output_type
= info
->output_type
;
169 path
->overlay_num
= info
->overlay_num
;
170 path
->plat_data
= info
->plat_data
;
171 path
->ops
.set_mode
= info
->set_mode
;
173 mutex_lock(&disp_lock
);
175 list_for_each_entry(panel
, &panel_list
, node
) {
176 if (!strcmp(info
->name
, panel
->plat_path_name
)) {
177 dev_info(path
->dev
, "get panel %s\n", panel
->name
);
183 dev_info(path
->dev
, "register %s, overlay_num %d\n",
184 path
->name
, path
->overlay_num
);
186 /* default op set: if already set by driver, never cover it */
187 if (!path
->ops
.check_status
)
188 path
->ops
.check_status
= path_check_status
;
189 if (!path
->ops
.get_overlay
)
190 path
->ops
.get_overlay
= path_get_overlay
;
191 if (!path
->ops
.get_modelist
)
192 path
->ops
.get_modelist
= path_get_modelist
;
194 /* step3: init overlays */
195 for (i
= 0; i
< path
->overlay_num
; i
++) {
196 path
->overlays
[i
].path
= path
;
197 path
->overlays
[i
].id
= i
;
198 mutex_init(&path
->overlays
[i
].access_ok
);
199 path
->overlays
[i
].ops
= info
->overlay_ops
;
202 /* add to pathlist */
203 list_add_tail(&path
->node
, &path_list
);
205 mutex_unlock(&disp_lock
);
208 EXPORT_SYMBOL_GPL(mmp_register_path
);
211 * mmp_unregister_path - unregister and destroy path
212 * @p: path to be destroyed.
214 * this function registers path and destroys it.
216 void mmp_unregister_path(struct mmp_path
*path
)
223 mutex_lock(&disp_lock
);
224 /* del from pathlist */
225 list_del(&path
->node
);
227 /* deinit overlays */
228 for (i
= 0; i
< path
->overlay_num
; i
++)
229 mutex_destroy(&path
->overlays
[i
].access_ok
);
231 mutex_destroy(&path
->access_ok
);
234 mutex_unlock(&disp_lock
);
236 EXPORT_SYMBOL_GPL(mmp_unregister_path
);
238 MODULE_AUTHOR("Zhou Zhu <zzhu3@marvell.com>");
239 MODULE_DESCRIPTION("Marvell MMP display framework");
240 MODULE_LICENSE("GPL");