core.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /*
  2. * linux/drivers/video/mmp/common.c
  3. * This driver is a common framework for Marvell Display Controller
  4. *
  5. * Copyright (C) 2012 Marvell Technology Group Ltd.
  6. * Authors: Zhou Zhu <zzhu3@marvell.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License as published by the
  10. * Free Software Foundation; either version 2 of the License, or (at your
  11. * option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful, but WITHOUT
  14. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  16. * more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along with
  19. * this program. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. #include <linux/slab.h>
  23. #include <linux/dma-mapping.h>
  24. #include <linux/export.h>
  25. #include <video/mmp_disp.h>
  26. static struct mmp_overlay *path_get_overlay(struct mmp_path *path,
  27. int overlay_id)
  28. {
  29. if (path && overlay_id < path->overlay_num)
  30. return &path->overlays[overlay_id];
  31. return NULL;
  32. }
  33. static int path_check_status(struct mmp_path *path)
  34. {
  35. int i;
  36. for (i = 0; i < path->overlay_num; i++)
  37. if (path->overlays[i].status)
  38. return 1;
  39. return 0;
  40. }
  41. /*
  42. * Get modelist write pointer of modelist.
  43. * It also returns modelist number
  44. * this function fetches modelist from phy/panel:
  45. * for HDMI/parallel or dsi to hdmi cases, get from phy
  46. * or get from panel
  47. */
  48. static int path_get_modelist(struct mmp_path *path,
  49. struct mmp_mode **modelist)
  50. {
  51. BUG_ON(!path || !modelist);
  52. if (path->panel && path->panel->get_modelist)
  53. return path->panel->get_modelist(path->panel, modelist);
  54. return 0;
  55. }
  56. /*
  57. * panel list is used to pair panel/path when path/panel registered
  58. * path list is used for both buffer driver and platdriver
  59. * plat driver do path register/unregister
  60. * panel driver do panel register/unregister
  61. * buffer driver get registered path
  62. */
  63. static LIST_HEAD(panel_list);
  64. static LIST_HEAD(path_list);
  65. static DEFINE_MUTEX(disp_lock);
  66. /*
  67. * mmp_register_panel - register panel to panel_list and connect to path
  68. * @p: panel to be registered
  69. *
  70. * this function provides interface for panel drivers to register panel
  71. * to panel_list and connect to path which matchs panel->plat_path_name.
  72. * no error returns when no matching path is found as path register after
  73. * panel register is permitted.
  74. */
  75. void mmp_register_panel(struct mmp_panel *panel)
  76. {
  77. struct mmp_path *path;
  78. mutex_lock(&disp_lock);
  79. /* add */
  80. 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",
  85. path->name);
  86. path->panel = panel;
  87. break;
  88. }
  89. }
  90. mutex_unlock(&disp_lock);
  91. }
  92. EXPORT_SYMBOL_GPL(mmp_register_panel);
  93. /*
  94. * mmp_unregister_panel - unregister panel from panel_list and disconnect
  95. * @p: panel to be unregistered
  96. *
  97. * this function provides interface for panel drivers to unregister panel
  98. * from panel_list and disconnect from path.
  99. */
  100. void mmp_unregister_panel(struct mmp_panel *panel)
  101. {
  102. struct mmp_path *path;
  103. mutex_lock(&disp_lock);
  104. list_del(&panel->node);
  105. list_for_each_entry(path, &path_list, node) {
  106. if (path->panel && path->panel == panel) {
  107. dev_info(panel->dev, "disconnect from path %s\n",
  108. path->name);
  109. path->panel = NULL;
  110. break;
  111. }
  112. }
  113. mutex_unlock(&disp_lock);
  114. }
  115. EXPORT_SYMBOL_GPL(mmp_unregister_panel);
  116. /*
  117. * mmp_get_path - get path by name
  118. * @p: path name
  119. *
  120. * this function checks path name in path_list and return matching path
  121. * return NULL if no matching path
  122. */
  123. struct mmp_path *mmp_get_path(const char *name)
  124. {
  125. struct mmp_path *path;
  126. int found = 0;
  127. mutex_lock(&disp_lock);
  128. list_for_each_entry(path, &path_list, node) {
  129. if (!strcmp(name, path->name)) {
  130. found = 1;
  131. break;
  132. }
  133. }
  134. mutex_unlock(&disp_lock);
  135. return found ? path : NULL;
  136. }
  137. EXPORT_SYMBOL_GPL(mmp_get_path);
  138. /*
  139. * mmp_register_path - init and register path by path_info
  140. * @p: path info provided by display controller
  141. *
  142. * this function init by path info and register path to path_list
  143. * this function also try to connect path with panel by name
  144. */
  145. struct mmp_path *mmp_register_path(struct mmp_path_info *info)
  146. {
  147. int i;
  148. size_t size;
  149. struct mmp_path *path = NULL;
  150. struct mmp_panel *panel;
  151. size = sizeof(struct mmp_path)
  152. + sizeof(struct mmp_overlay) * info->overlay_num;
  153. path = kzalloc(size, GFP_KERNEL);
  154. if (!path)
  155. return NULL;
  156. /* path set */
  157. mutex_init(&path->access_ok);
  158. path->dev = info->dev;
  159. path->id = info->id;
  160. path->name = info->name;
  161. path->output_type = info->output_type;
  162. path->overlay_num = info->overlay_num;
  163. path->plat_data = info->plat_data;
  164. path->ops.set_mode = info->set_mode;
  165. mutex_lock(&disp_lock);
  166. /* get panel */
  167. list_for_each_entry(panel, &panel_list, node) {
  168. if (!strcmp(info->name, panel->plat_path_name)) {
  169. dev_info(path->dev, "get panel %s\n", panel->name);
  170. path->panel = panel;
  171. break;
  172. }
  173. }
  174. dev_info(path->dev, "register %s, overlay_num %d\n",
  175. path->name, path->overlay_num);
  176. /* default op set: if already set by driver, never cover it */
  177. if (!path->ops.check_status)
  178. path->ops.check_status = path_check_status;
  179. if (!path->ops.get_overlay)
  180. path->ops.get_overlay = path_get_overlay;
  181. if (!path->ops.get_modelist)
  182. path->ops.get_modelist = path_get_modelist;
  183. /* step3: init overlays */
  184. for (i = 0; i < path->overlay_num; i++) {
  185. path->overlays[i].path = path;
  186. path->overlays[i].id = i;
  187. mutex_init(&path->overlays[i].access_ok);
  188. path->overlays[i].ops = info->overlay_ops;
  189. }
  190. /* add to pathlist */
  191. list_add_tail(&path->node, &path_list);
  192. mutex_unlock(&disp_lock);
  193. return path;
  194. }
  195. EXPORT_SYMBOL_GPL(mmp_register_path);
  196. /*
  197. * mmp_unregister_path - unregister and destroy path
  198. * @p: path to be destroyed.
  199. *
  200. * this function registers path and destroys it.
  201. */
  202. void mmp_unregister_path(struct mmp_path *path)
  203. {
  204. int i;
  205. if (!path)
  206. return;
  207. mutex_lock(&disp_lock);
  208. /* del from pathlist */
  209. list_del(&path->node);
  210. /* deinit overlays */
  211. for (i = 0; i < path->overlay_num; i++)
  212. mutex_destroy(&path->overlays[i].access_ok);
  213. mutex_destroy(&path->access_ok);
  214. kfree(path);
  215. mutex_unlock(&disp_lock);
  216. }
  217. EXPORT_SYMBOL_GPL(mmp_unregister_path);