Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * linux/drivers/video/mmp/common.c
0004  * This driver is a common framework for Marvell Display Controller
0005  *
0006  * Copyright (C) 2012 Marvell Technology Group Ltd.
0007  * Authors: Zhou Zhu <zzhu3@marvell.com>
0008  */
0009 
0010 #include <linux/slab.h>
0011 #include <linux/dma-mapping.h>
0012 #include <linux/export.h>
0013 #include <linux/module.h>
0014 #include <video/mmp_disp.h>
0015 
0016 static struct mmp_overlay *path_get_overlay(struct mmp_path *path,
0017         int overlay_id)
0018 {
0019     if (path && overlay_id < path->overlay_num)
0020         return &path->overlays[overlay_id];
0021     return NULL;
0022 }
0023 
0024 static int path_check_status(struct mmp_path *path)
0025 {
0026     int i;
0027     for (i = 0; i < path->overlay_num; i++)
0028         if (path->overlays[i].status)
0029             return 1;
0030 
0031     return 0;
0032 }
0033 
0034 /*
0035  * Get modelist write pointer of modelist.
0036  * It also returns modelist number
0037  * this function fetches modelist from phy/panel:
0038  *   for HDMI/parallel or dsi to hdmi cases, get from phy
0039  *   or get from panel
0040  */
0041 static int path_get_modelist(struct mmp_path *path,
0042         struct mmp_mode **modelist)
0043 {
0044     BUG_ON(!path || !modelist);
0045 
0046     if (path->panel && path->panel->get_modelist)
0047         return path->panel->get_modelist(path->panel, modelist);
0048 
0049     return 0;
0050 }
0051 
0052 /*
0053  * panel list is used to pair panel/path when path/panel registered
0054  * path list is used for both buffer driver and platdriver
0055  * plat driver do path register/unregister
0056  * panel driver do panel register/unregister
0057  * buffer driver get registered path
0058  */
0059 static LIST_HEAD(panel_list);
0060 static LIST_HEAD(path_list);
0061 static DEFINE_MUTEX(disp_lock);
0062 
0063 /*
0064  * mmp_register_panel - register panel to panel_list and connect to path
0065  * @p: panel to be registered
0066  *
0067  * this function provides interface for panel drivers to register panel
0068  * to panel_list and connect to path which matchs panel->plat_path_name.
0069  * no error returns when no matching path is found as path register after
0070  * panel register is permitted.
0071  */
0072 void mmp_register_panel(struct mmp_panel *panel)
0073 {
0074     struct mmp_path *path;
0075 
0076     mutex_lock(&disp_lock);
0077 
0078     /* add */
0079     list_add_tail(&panel->node, &panel_list);
0080 
0081     /* try to register to path */
0082     list_for_each_entry(path, &path_list, node) {
0083         if (!strcmp(panel->plat_path_name, path->name)) {
0084             dev_info(panel->dev, "connect to path %s\n",
0085                 path->name);
0086             path->panel = panel;
0087             break;
0088         }
0089     }
0090 
0091     mutex_unlock(&disp_lock);
0092 }
0093 EXPORT_SYMBOL_GPL(mmp_register_panel);
0094 
0095 /*
0096  * mmp_unregister_panel - unregister panel from panel_list and disconnect
0097  * @p: panel to be unregistered
0098  *
0099  * this function provides interface for panel drivers to unregister panel
0100  * from panel_list and disconnect from path.
0101  */
0102 void mmp_unregister_panel(struct mmp_panel *panel)
0103 {
0104     struct mmp_path *path;
0105 
0106     mutex_lock(&disp_lock);
0107     list_del(&panel->node);
0108 
0109     list_for_each_entry(path, &path_list, node) {
0110         if (path->panel && path->panel == panel) {
0111             dev_info(panel->dev, "disconnect from path %s\n",
0112                 path->name);
0113             path->panel = NULL;
0114             break;
0115         }
0116     }
0117     mutex_unlock(&disp_lock);
0118 }
0119 EXPORT_SYMBOL_GPL(mmp_unregister_panel);
0120 
0121 /*
0122  * mmp_get_path - get path by name
0123  * @p: path name
0124  *
0125  * this function checks path name in path_list and return matching path
0126  * return NULL if no matching path
0127  */
0128 struct mmp_path *mmp_get_path(const char *name)
0129 {
0130     struct mmp_path *path = NULL, *iter;
0131 
0132     mutex_lock(&disp_lock);
0133     list_for_each_entry(iter, &path_list, node) {
0134         if (!strcmp(name, iter->name)) {
0135             path = iter;
0136             break;
0137         }
0138     }
0139     mutex_unlock(&disp_lock);
0140 
0141     return path;
0142 }
0143 EXPORT_SYMBOL_GPL(mmp_get_path);
0144 
0145 /*
0146  * mmp_register_path - init and register path by path_info
0147  * @p: path info provided by display controller
0148  *
0149  * this function init by path info and register path to path_list
0150  * this function also try to connect path with panel by name
0151  */
0152 struct mmp_path *mmp_register_path(struct mmp_path_info *info)
0153 {
0154     int i;
0155     struct mmp_path *path = NULL;
0156     struct mmp_panel *panel;
0157 
0158     path = kzalloc(struct_size(path, overlays, info->overlay_num),
0159                GFP_KERNEL);
0160     if (!path)
0161         return NULL;
0162 
0163     /* path set */
0164     mutex_init(&path->access_ok);
0165     path->dev = info->dev;
0166     path->id = info->id;
0167     path->name = info->name;
0168     path->output_type = info->output_type;
0169     path->overlay_num = info->overlay_num;
0170     path->plat_data = info->plat_data;
0171     path->ops.set_mode = info->set_mode;
0172 
0173     mutex_lock(&disp_lock);
0174     /* get panel */
0175     list_for_each_entry(panel, &panel_list, node) {
0176         if (!strcmp(info->name, panel->plat_path_name)) {
0177             dev_info(path->dev, "get panel %s\n", panel->name);
0178             path->panel = panel;
0179             break;
0180         }
0181     }
0182 
0183     dev_info(path->dev, "register %s, overlay_num %d\n",
0184             path->name, path->overlay_num);
0185 
0186     /* default op set: if already set by driver, never cover it */
0187     if (!path->ops.check_status)
0188         path->ops.check_status = path_check_status;
0189     if (!path->ops.get_overlay)
0190         path->ops.get_overlay = path_get_overlay;
0191     if (!path->ops.get_modelist)
0192         path->ops.get_modelist = path_get_modelist;
0193 
0194     /* step3: init overlays */
0195     for (i = 0; i < path->overlay_num; i++) {
0196         path->overlays[i].path = path;
0197         path->overlays[i].id = i;
0198         mutex_init(&path->overlays[i].access_ok);
0199         path->overlays[i].ops = info->overlay_ops;
0200     }
0201 
0202     /* add to pathlist */
0203     list_add_tail(&path->node, &path_list);
0204 
0205     mutex_unlock(&disp_lock);
0206     return path;
0207 }
0208 EXPORT_SYMBOL_GPL(mmp_register_path);
0209 
0210 /*
0211  * mmp_unregister_path - unregister and destroy path
0212  * @p: path to be destroyed.
0213  *
0214  * this function registers path and destroys it.
0215  */
0216 void mmp_unregister_path(struct mmp_path *path)
0217 {
0218     int i;
0219 
0220     if (!path)
0221         return;
0222 
0223     mutex_lock(&disp_lock);
0224     /* del from pathlist */
0225     list_del(&path->node);
0226 
0227     /* deinit overlays */
0228     for (i = 0; i < path->overlay_num; i++)
0229         mutex_destroy(&path->overlays[i].access_ok);
0230 
0231     mutex_destroy(&path->access_ok);
0232 
0233     kfree(path);
0234     mutex_unlock(&disp_lock);
0235 }
0236 EXPORT_SYMBOL_GPL(mmp_unregister_path);
0237 
0238 MODULE_AUTHOR("Zhou Zhu <zzhu3@marvell.com>");
0239 MODULE_DESCRIPTION("Marvell MMP display framework");
0240 MODULE_LICENSE("GPL");