11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 259393bb9SZhou Zhu /* 359393bb9SZhou Zhu * linux/drivers/video/mmp/common.c 459393bb9SZhou Zhu * This driver is a common framework for Marvell Display Controller 559393bb9SZhou Zhu * 659393bb9SZhou Zhu * Copyright (C) 2012 Marvell Technology Group Ltd. 759393bb9SZhou Zhu * Authors: Zhou Zhu <zzhu3@marvell.com> 859393bb9SZhou Zhu */ 959393bb9SZhou Zhu 1059393bb9SZhou Zhu #include <linux/slab.h> 1159393bb9SZhou Zhu #include <linux/dma-mapping.h> 1259393bb9SZhou Zhu #include <linux/export.h> 13c1530ac5SArnd Bergmann #include <linux/module.h> 1459393bb9SZhou Zhu #include <video/mmp_disp.h> 1559393bb9SZhou Zhu 1659393bb9SZhou Zhu static struct mmp_overlay *path_get_overlay(struct mmp_path *path, 1759393bb9SZhou Zhu int overlay_id) 1859393bb9SZhou Zhu { 1959393bb9SZhou Zhu if (path && overlay_id < path->overlay_num) 2059393bb9SZhou Zhu return &path->overlays[overlay_id]; 216fc19c40SDan Carpenter return NULL; 2259393bb9SZhou Zhu } 2359393bb9SZhou Zhu 2459393bb9SZhou Zhu static int path_check_status(struct mmp_path *path) 2559393bb9SZhou Zhu { 2659393bb9SZhou Zhu int i; 2759393bb9SZhou Zhu for (i = 0; i < path->overlay_num; i++) 2859393bb9SZhou Zhu if (path->overlays[i].status) 2959393bb9SZhou Zhu return 1; 3059393bb9SZhou Zhu 3159393bb9SZhou Zhu return 0; 3259393bb9SZhou Zhu } 3359393bb9SZhou Zhu 3459393bb9SZhou Zhu /* 3559393bb9SZhou Zhu * Get modelist write pointer of modelist. 3659393bb9SZhou Zhu * It also returns modelist number 3759393bb9SZhou Zhu * this function fetches modelist from phy/panel: 3859393bb9SZhou Zhu * for HDMI/parallel or dsi to hdmi cases, get from phy 3959393bb9SZhou Zhu * or get from panel 4059393bb9SZhou Zhu */ 4159393bb9SZhou Zhu static int path_get_modelist(struct mmp_path *path, 4259393bb9SZhou Zhu struct mmp_mode **modelist) 4359393bb9SZhou Zhu { 4459393bb9SZhou Zhu BUG_ON(!path || !modelist); 4559393bb9SZhou Zhu 4659393bb9SZhou Zhu if (path->panel && path->panel->get_modelist) 4759393bb9SZhou Zhu return path->panel->get_modelist(path->panel, modelist); 4859393bb9SZhou Zhu 4959393bb9SZhou Zhu return 0; 5059393bb9SZhou Zhu } 5159393bb9SZhou Zhu 5259393bb9SZhou Zhu /* 5359393bb9SZhou Zhu * panel list is used to pair panel/path when path/panel registered 5459393bb9SZhou Zhu * path list is used for both buffer driver and platdriver 5559393bb9SZhou Zhu * plat driver do path register/unregister 5659393bb9SZhou Zhu * panel driver do panel register/unregister 5759393bb9SZhou Zhu * buffer driver get registered path 5859393bb9SZhou Zhu */ 5959393bb9SZhou Zhu static LIST_HEAD(panel_list); 6059393bb9SZhou Zhu static LIST_HEAD(path_list); 6159393bb9SZhou Zhu static DEFINE_MUTEX(disp_lock); 6259393bb9SZhou Zhu 6359393bb9SZhou Zhu /* 6459393bb9SZhou Zhu * mmp_register_panel - register panel to panel_list and connect to path 6559393bb9SZhou Zhu * @p: panel to be registered 6659393bb9SZhou Zhu * 6759393bb9SZhou Zhu * this function provides interface for panel drivers to register panel 6859393bb9SZhou Zhu * to panel_list and connect to path which matchs panel->plat_path_name. 6959393bb9SZhou Zhu * no error returns when no matching path is found as path register after 7059393bb9SZhou Zhu * panel register is permitted. 7159393bb9SZhou Zhu */ 7259393bb9SZhou Zhu void mmp_register_panel(struct mmp_panel *panel) 7359393bb9SZhou Zhu { 7459393bb9SZhou Zhu struct mmp_path *path; 7559393bb9SZhou Zhu 7659393bb9SZhou Zhu mutex_lock(&disp_lock); 7759393bb9SZhou Zhu 7859393bb9SZhou Zhu /* add */ 7959393bb9SZhou Zhu list_add_tail(&panel->node, &panel_list); 8059393bb9SZhou Zhu 8159393bb9SZhou Zhu /* try to register to path */ 8259393bb9SZhou Zhu list_for_each_entry(path, &path_list, node) { 8359393bb9SZhou Zhu if (!strcmp(panel->plat_path_name, path->name)) { 8459393bb9SZhou Zhu dev_info(panel->dev, "connect to path %s\n", 8559393bb9SZhou Zhu path->name); 8659393bb9SZhou Zhu path->panel = panel; 8759393bb9SZhou Zhu break; 8859393bb9SZhou Zhu } 8959393bb9SZhou Zhu } 9059393bb9SZhou Zhu 9159393bb9SZhou Zhu mutex_unlock(&disp_lock); 9259393bb9SZhou Zhu } 9359393bb9SZhou Zhu EXPORT_SYMBOL_GPL(mmp_register_panel); 9459393bb9SZhou Zhu 9559393bb9SZhou Zhu /* 9659393bb9SZhou Zhu * mmp_unregister_panel - unregister panel from panel_list and disconnect 9759393bb9SZhou Zhu * @p: panel to be unregistered 9859393bb9SZhou Zhu * 9959393bb9SZhou Zhu * this function provides interface for panel drivers to unregister panel 10059393bb9SZhou Zhu * from panel_list and disconnect from path. 10159393bb9SZhou Zhu */ 10259393bb9SZhou Zhu void mmp_unregister_panel(struct mmp_panel *panel) 10359393bb9SZhou Zhu { 10459393bb9SZhou Zhu struct mmp_path *path; 10559393bb9SZhou Zhu 10659393bb9SZhou Zhu mutex_lock(&disp_lock); 10759393bb9SZhou Zhu list_del(&panel->node); 10859393bb9SZhou Zhu 10959393bb9SZhou Zhu list_for_each_entry(path, &path_list, node) { 11059393bb9SZhou Zhu if (path->panel && path->panel == panel) { 11159393bb9SZhou Zhu dev_info(panel->dev, "disconnect from path %s\n", 11259393bb9SZhou Zhu path->name); 11359393bb9SZhou Zhu path->panel = NULL; 11459393bb9SZhou Zhu break; 11559393bb9SZhou Zhu } 11659393bb9SZhou Zhu } 11759393bb9SZhou Zhu mutex_unlock(&disp_lock); 11859393bb9SZhou Zhu } 11959393bb9SZhou Zhu EXPORT_SYMBOL_GPL(mmp_unregister_panel); 12059393bb9SZhou Zhu 12159393bb9SZhou Zhu /* 12259393bb9SZhou Zhu * mmp_get_path - get path by name 12359393bb9SZhou Zhu * @p: path name 12459393bb9SZhou Zhu * 12559393bb9SZhou Zhu * this function checks path name in path_list and return matching path 12659393bb9SZhou Zhu * return NULL if no matching path 12759393bb9SZhou Zhu */ 12859393bb9SZhou Zhu struct mmp_path *mmp_get_path(const char *name) 12959393bb9SZhou Zhu { 13059393bb9SZhou Zhu struct mmp_path *path; 13159393bb9SZhou Zhu int found = 0; 13259393bb9SZhou Zhu 13359393bb9SZhou Zhu mutex_lock(&disp_lock); 13459393bb9SZhou Zhu list_for_each_entry(path, &path_list, node) { 13559393bb9SZhou Zhu if (!strcmp(name, path->name)) { 13659393bb9SZhou Zhu found = 1; 13759393bb9SZhou Zhu break; 13859393bb9SZhou Zhu } 13959393bb9SZhou Zhu } 14059393bb9SZhou Zhu mutex_unlock(&disp_lock); 14159393bb9SZhou Zhu 14259393bb9SZhou Zhu return found ? path : NULL; 14359393bb9SZhou Zhu } 14459393bb9SZhou Zhu EXPORT_SYMBOL_GPL(mmp_get_path); 14559393bb9SZhou Zhu 14659393bb9SZhou Zhu /* 14759393bb9SZhou Zhu * mmp_register_path - init and register path by path_info 14859393bb9SZhou Zhu * @p: path info provided by display controller 14959393bb9SZhou Zhu * 15059393bb9SZhou Zhu * this function init by path info and register path to path_list 15159393bb9SZhou Zhu * this function also try to connect path with panel by name 15259393bb9SZhou Zhu */ 15359393bb9SZhou Zhu struct mmp_path *mmp_register_path(struct mmp_path_info *info) 15459393bb9SZhou Zhu { 15559393bb9SZhou Zhu int i; 15659393bb9SZhou Zhu struct mmp_path *path = NULL; 15759393bb9SZhou Zhu struct mmp_panel *panel; 15859393bb9SZhou Zhu 159*06b1f4b9SGustavo A. R. Silva path = kzalloc(struct_size(path, overlays, info->overlay_num), 160*06b1f4b9SGustavo A. R. Silva GFP_KERNEL); 16159393bb9SZhou Zhu if (!path) 1624ac8bd61SDan Carpenter return NULL; 16359393bb9SZhou Zhu 16459393bb9SZhou Zhu /* path set */ 16559393bb9SZhou Zhu mutex_init(&path->access_ok); 16659393bb9SZhou Zhu path->dev = info->dev; 16759393bb9SZhou Zhu path->id = info->id; 16859393bb9SZhou Zhu path->name = info->name; 16959393bb9SZhou Zhu path->output_type = info->output_type; 17059393bb9SZhou Zhu path->overlay_num = info->overlay_num; 17159393bb9SZhou Zhu path->plat_data = info->plat_data; 17259393bb9SZhou Zhu path->ops.set_mode = info->set_mode; 17359393bb9SZhou Zhu 17459393bb9SZhou Zhu mutex_lock(&disp_lock); 17559393bb9SZhou Zhu /* get panel */ 17659393bb9SZhou Zhu list_for_each_entry(panel, &panel_list, node) { 17759393bb9SZhou Zhu if (!strcmp(info->name, panel->plat_path_name)) { 17859393bb9SZhou Zhu dev_info(path->dev, "get panel %s\n", panel->name); 17959393bb9SZhou Zhu path->panel = panel; 18059393bb9SZhou Zhu break; 18159393bb9SZhou Zhu } 18259393bb9SZhou Zhu } 18359393bb9SZhou Zhu 18459393bb9SZhou Zhu dev_info(path->dev, "register %s, overlay_num %d\n", 18559393bb9SZhou Zhu path->name, path->overlay_num); 18659393bb9SZhou Zhu 18759393bb9SZhou Zhu /* default op set: if already set by driver, never cover it */ 18859393bb9SZhou Zhu if (!path->ops.check_status) 18959393bb9SZhou Zhu path->ops.check_status = path_check_status; 19059393bb9SZhou Zhu if (!path->ops.get_overlay) 19159393bb9SZhou Zhu path->ops.get_overlay = path_get_overlay; 19259393bb9SZhou Zhu if (!path->ops.get_modelist) 19359393bb9SZhou Zhu path->ops.get_modelist = path_get_modelist; 19459393bb9SZhou Zhu 19559393bb9SZhou Zhu /* step3: init overlays */ 19659393bb9SZhou Zhu for (i = 0; i < path->overlay_num; i++) { 19759393bb9SZhou Zhu path->overlays[i].path = path; 19859393bb9SZhou Zhu path->overlays[i].id = i; 19959393bb9SZhou Zhu mutex_init(&path->overlays[i].access_ok); 20059393bb9SZhou Zhu path->overlays[i].ops = info->overlay_ops; 20159393bb9SZhou Zhu } 20259393bb9SZhou Zhu 20359393bb9SZhou Zhu /* add to pathlist */ 20459393bb9SZhou Zhu list_add_tail(&path->node, &path_list); 20559393bb9SZhou Zhu 20659393bb9SZhou Zhu mutex_unlock(&disp_lock); 20759393bb9SZhou Zhu return path; 20859393bb9SZhou Zhu } 20959393bb9SZhou Zhu EXPORT_SYMBOL_GPL(mmp_register_path); 21059393bb9SZhou Zhu 21159393bb9SZhou Zhu /* 2129e09d00fSMarkus Elfring * mmp_unregister_path - unregister and destroy path 21323c12eacSMarkus Elfring * @p: path to be destroyed. 21459393bb9SZhou Zhu * 2159e09d00fSMarkus Elfring * this function registers path and destroys it. 21659393bb9SZhou Zhu */ 21759393bb9SZhou Zhu void mmp_unregister_path(struct mmp_path *path) 21859393bb9SZhou Zhu { 21959393bb9SZhou Zhu int i; 22059393bb9SZhou Zhu 22159393bb9SZhou Zhu if (!path) 22259393bb9SZhou Zhu return; 22359393bb9SZhou Zhu 22459393bb9SZhou Zhu mutex_lock(&disp_lock); 22559393bb9SZhou Zhu /* del from pathlist */ 22659393bb9SZhou Zhu list_del(&path->node); 22759393bb9SZhou Zhu 22859393bb9SZhou Zhu /* deinit overlays */ 22959393bb9SZhou Zhu for (i = 0; i < path->overlay_num; i++) 23059393bb9SZhou Zhu mutex_destroy(&path->overlays[i].access_ok); 23159393bb9SZhou Zhu 23259393bb9SZhou Zhu mutex_destroy(&path->access_ok); 23359393bb9SZhou Zhu 23459393bb9SZhou Zhu kfree(path); 23559393bb9SZhou Zhu mutex_unlock(&disp_lock); 23659393bb9SZhou Zhu } 23759393bb9SZhou Zhu EXPORT_SYMBOL_GPL(mmp_unregister_path); 238c1530ac5SArnd Bergmann 239c1530ac5SArnd Bergmann MODULE_AUTHOR("Zhou Zhu <zzhu3@marvell.com>"); 240c1530ac5SArnd Bergmann MODULE_DESCRIPTION("Marvell MMP display framework"); 241c1530ac5SArnd Bergmann MODULE_LICENSE("GPL"); 242