linux/drivers/video/fbdev/mmp/core.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * linux/drivers/video/mmp/common.c
   4 * This driver is a common framework for Marvell Display Controller
   5 *
   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 number
  37 * this function fetches modelist from phy/panel:
  38 *   for HDMI/parallel or dsi to hdmi cases, get from phy
  39 *   or get from panel
  40 */
  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 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
  58 */
  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 path
  65 * @p: panel to be registered
  66 *
  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.
  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 disconnect
  97 * @p: panel to be unregistered
  98 *
  99 * this function provides interface for panel drivers to unregister panel
 100 * 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 name
 123 * @p: path name
 124 *
 125 * this function checks path name in path_list and return matching path
 126 * return NULL if no matching path
 127 */
 128struct mmp_path *mmp_get_path(const char *name)
 129{
 130        struct mmp_path *path;
 131        int found = 0;
 132
 133        mutex_lock(&disp_lock);
 134        list_for_each_entry(path, &path_list, node) {
 135                if (!strcmp(name, path->name)) {
 136                        found = 1;
 137                        break;
 138                }
 139        }
 140        mutex_unlock(&disp_lock);
 141
 142        return found ? path : NULL;
 143}
 144EXPORT_SYMBOL_GPL(mmp_get_path);
 145
 146/*
 147 * mmp_register_path - init and register path by path_info
 148 * @p: path info provided by display controller
 149 *
 150 * this function init by path info and register path to path_list
 151 * this function also try to connect path with panel by name
 152 */
 153struct mmp_path *mmp_register_path(struct mmp_path_info *info)
 154{
 155        int i;
 156        struct mmp_path *path = NULL;
 157        struct mmp_panel *panel;
 158
 159        path = kzalloc(struct_size(path, overlays, info->overlay_num),
 160                       GFP_KERNEL);
 161        if (!path)
 162                return NULL;
 163
 164        /* path set */
 165        mutex_init(&path->access_ok);
 166        path->dev = info->dev;
 167        path->id = info->id;
 168        path->name = info->name;
 169        path->output_type = info->output_type;
 170        path->overlay_num = info->overlay_num;
 171        path->plat_data = info->plat_data;
 172        path->ops.set_mode = info->set_mode;
 173
 174        mutex_lock(&disp_lock);
 175        /* get panel */
 176        list_for_each_entry(panel, &panel_list, node) {
 177                if (!strcmp(info->name, panel->plat_path_name)) {
 178                        dev_info(path->dev, "get panel %s\n", panel->name);
 179                        path->panel = panel;
 180                        break;
 181                }
 182        }
 183
 184        dev_info(path->dev, "register %s, overlay_num %d\n",
 185                        path->name, path->overlay_num);
 186
 187        /* default op set: if already set by driver, never cover it */
 188        if (!path->ops.check_status)
 189                path->ops.check_status = path_check_status;
 190        if (!path->ops.get_overlay)
 191                path->ops.get_overlay = path_get_overlay;
 192        if (!path->ops.get_modelist)
 193                path->ops.get_modelist = path_get_modelist;
 194
 195        /* step3: init overlays */
 196        for (i = 0; i < path->overlay_num; i++) {
 197                path->overlays[i].path = path;
 198                path->overlays[i].id = i;
 199                mutex_init(&path->overlays[i].access_ok);
 200                path->overlays[i].ops = info->overlay_ops;
 201        }
 202
 203        /* add to pathlist */
 204        list_add_tail(&path->node, &path_list);
 205
 206        mutex_unlock(&disp_lock);
 207        return path;
 208}
 209EXPORT_SYMBOL_GPL(mmp_register_path);
 210
 211/*
 212 * mmp_unregister_path - unregister and destroy path
 213 * @p: path to be destroyed.
 214 *
 215 * this function registers path and destroys it.
 216 */
 217void mmp_unregister_path(struct mmp_path *path)
 218{
 219        int i;
 220
 221        if (!path)
 222                return;
 223
 224        mutex_lock(&disp_lock);
 225        /* del from pathlist */
 226        list_del(&path->node);
 227
 228        /* deinit overlays */
 229        for (i = 0; i < path->overlay_num; i++)
 230                mutex_destroy(&path->overlays[i].access_ok);
 231
 232        mutex_destroy(&path->access_ok);
 233
 234        kfree(path);
 235        mutex_unlock(&disp_lock);
 236}
 237EXPORT_SYMBOL_GPL(mmp_unregister_path);
 238
 239MODULE_AUTHOR("Zhou Zhu <zzhu3@marvell.com>");
 240MODULE_DESCRIPTION("Marvell MMP display framework");
 241MODULE_LICENSE("GPL");
 242