241 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * linux/drivers/video/mmp/common.c4 * This driver is a common framework for Marvell Display Controller5 *6 * Copyright (C) 2012 Marvell Technology Group Ltd.7 * Authors: Zhou Zhu <zzhu3@marvell.com>8 */9 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>15 16static struct mmp_overlay *path_get_overlay(struct mmp_path *path,17 int overlay_id)18{19 if (path && overlay_id < path->overlay_num)20 return &path->overlays[overlay_id];21 return NULL;22}23 24static int path_check_status(struct mmp_path *path)25{26 int i;27 for (i = 0; i < path->overlay_num; i++)28 if (path->overlays[i].status)29 return 1;30 31 return 0;32}33 34/*35 * Get modelist write pointer of modelist.36 * It also returns modelist number37 * this function fetches modelist from phy/panel:38 * for HDMI/parallel or dsi to hdmi cases, get from phy39 * or get from panel40 */41static int path_get_modelist(struct mmp_path *path,42 struct mmp_mode **modelist)43{44 BUG_ON(!path || !modelist);45 46 if (path->panel && path->panel->get_modelist)47 return path->panel->get_modelist(path->panel, modelist);48 49 return 0;50}51 52/*53 * panel list is used to pair panel/path when path/panel registered54 * path list is used for both buffer driver and platdriver55 * plat driver do path register/unregister56 * panel driver do panel register/unregister57 * buffer driver get registered path58 */59static LIST_HEAD(panel_list);60static LIST_HEAD(path_list);61static DEFINE_MUTEX(disp_lock);62 63/*64 * mmp_register_panel - register panel to panel_list and connect to path65 * @p: panel to be registered66 *67 * this function provides interface for panel drivers to register panel68 * 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 after70 * panel register is permitted.71 */72void mmp_register_panel(struct mmp_panel *panel)73{74 struct mmp_path *path;75 76 mutex_lock(&disp_lock);77 78 /* add */79 list_add_tail(&panel->node, &panel_list);80 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 91 mutex_unlock(&disp_lock);92}93EXPORT_SYMBOL_GPL(mmp_register_panel);94 95/*96 * mmp_unregister_panel - unregister panel from panel_list and disconnect97 * @p: panel to be unregistered98 *99 * this function provides interface for panel drivers to unregister panel100 * from panel_list and disconnect from path.101 */102void mmp_unregister_panel(struct mmp_panel *panel)103{104 struct mmp_path *path;105 106 mutex_lock(&disp_lock);107 list_del(&panel->node);108 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",112 path->name);113 path->panel = NULL;114 break;115 }116 }117 mutex_unlock(&disp_lock);118}119EXPORT_SYMBOL_GPL(mmp_unregister_panel);120 121/*122 * mmp_get_path - get path by name123 * @p: path name124 *125 * this function checks path name in path_list and return matching path126 * return NULL if no matching path127 */128struct mmp_path *mmp_get_path(const char *name)129{130 struct mmp_path *path = NULL, *iter;131 132 mutex_lock(&disp_lock);133 list_for_each_entry(iter, &path_list, node) {134 if (!strcmp(name, iter->name)) {135 path = iter;136 break;137 }138 }139 mutex_unlock(&disp_lock);140 141 return path;142}143EXPORT_SYMBOL_GPL(mmp_get_path);144 145/*146 * mmp_register_path - init and register path by path_info147 * @p: path info provided by display controller148 *149 * this function init by path info and register path to path_list150 * this function also try to connect path with panel by name151 */152struct mmp_path *mmp_register_path(struct mmp_path_info *info)153{154 int i;155 struct mmp_path *path = NULL;156 struct mmp_panel *panel;157 158 path = kzalloc(struct_size(path, overlays, info->overlay_num),159 GFP_KERNEL);160 if (!path)161 return NULL;162 163 /* path set */164 mutex_init(&path->access_ok);165 path->dev = info->dev;166 path->id = info->id;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;172 173 mutex_lock(&disp_lock);174 /* get panel */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);178 path->panel = panel;179 break;180 }181 }182 183 dev_info(path->dev, "register %s, overlay_num %d\n",184 path->name, path->overlay_num);185 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;193 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;200 }201 202 /* add to pathlist */203 list_add_tail(&path->node, &path_list);204 205 mutex_unlock(&disp_lock);206 return path;207}208EXPORT_SYMBOL_GPL(mmp_register_path);209 210/*211 * mmp_unregister_path - unregister and destroy path212 * @p: path to be destroyed.213 *214 * this function registers path and destroys it.215 */216void mmp_unregister_path(struct mmp_path *path)217{218 int i;219 220 if (!path)221 return;222 223 mutex_lock(&disp_lock);224 /* del from pathlist */225 list_del(&path->node);226 227 /* deinit overlays */228 for (i = 0; i < path->overlay_num; i++)229 mutex_destroy(&path->overlays[i].access_ok);230 231 mutex_destroy(&path->access_ok);232 233 kfree(path);234 mutex_unlock(&disp_lock);235}236EXPORT_SYMBOL_GPL(mmp_unregister_path);237 238MODULE_AUTHOR("Zhou Zhu <zzhu3@marvell.com>");239MODULE_DESCRIPTION("Marvell MMP display framework");240MODULE_LICENSE("GPL");241