linux/drivers/video/fbdev/mmp/core.c
<<
>>
Prefs
   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
  23#include <linux/slab.h>
  24#include <linux/dma-mapping.h>
  25#include <linux/export.h>
  26#include <linux/module.h>
  27#include <video/mmp_disp.h>
  28
  29static struct mmp_overlay *path_get_overlay(struct mmp_path *path,
  30                int overlay_id)
  31{
  32        if (path && overlay_id < path->overlay_num)
  33                return &path->overlays[overlay_id];
  34        return NULL;
  35}
  36
  37static int path_check_status(struct mmp_path *path)
  38{
  39        int i;
  40        for (i = 0; i < path->overlay_num; i++)
  41                if (path->overlays[i].status)
  42                        return 1;
  43
  44        return 0;
  45}
  46
  47/*
  48 * Get modelist write pointer of modelist.
  49 * It also returns modelist number
  50 * this function fetches modelist from phy/panel:
  51 *   for HDMI/parallel or dsi to hdmi cases, get from phy
  52 *   or get from panel
  53 */
  54static int path_get_modelist(struct mmp_path *path,
  55                struct mmp_mode **modelist)
  56{
  57        BUG_ON(!path || !modelist);
  58
  59        if (path->panel && path->panel->get_modelist)
  60                return path->panel->get_modelist(path->panel, modelist);
  61
  62        return 0;
  63}
  64
  65/*
  66 * panel list is used to pair panel/path when path/panel registered
  67 * path list is used for both buffer driver and platdriver
  68 * plat driver do path register/unregister
  69 * panel driver do panel register/unregister
  70 * buffer driver get registered path
  71 */
  72static LIST_HEAD(panel_list);
  73static LIST_HEAD(path_list);
  74static DEFINE_MUTEX(disp_lock);
  75
  76/*
  77 * mmp_register_panel - register panel to panel_list and connect to path
  78 * @p: panel to be registered
  79 *
  80 * this function provides interface for panel drivers to register panel
  81 * to panel_list and connect to path which matchs panel->plat_path_name.
  82 * no error returns when no matching path is found as path register after
  83 * panel register is permitted.
  84 */
  85void mmp_register_panel(struct mmp_panel *panel)
  86{
  87        struct mmp_path *path;
  88
  89        mutex_lock(&disp_lock);
  90
  91        /* add */
  92        list_add_tail(&panel->node, &panel_list);
  93
  94        /* try to register to path */
  95        list_for_each_entry(path, &path_list, node) {
  96                if (!strcmp(panel->plat_path_name, path->name)) {
  97                        dev_info(panel->dev, "connect to path %s\n",
  98                                path->name);
  99                        path->panel = panel;
 100                        break;
 101                }
 102        }
 103
 104        mutex_unlock(&disp_lock);
 105}
 106EXPORT_SYMBOL_GPL(mmp_register_panel);
 107
 108/*
 109 * mmp_unregister_panel - unregister panel from panel_list and disconnect
 110 * @p: panel to be unregistered
 111 *
 112 * this function provides interface for panel drivers to unregister panel
 113 * from panel_list and disconnect from path.
 114 */
 115void mmp_unregister_panel(struct mmp_panel *panel)
 116{
 117        struct mmp_path *path;
 118
 119        mutex_lock(&disp_lock);
 120        list_del(&panel->node);
 121
 122        list_for_each_entry(path, &path_list, node) {
 123                if (path->panel && path->panel == panel) {
 124                        dev_info(panel->dev, "disconnect from path %s\n",
 125                                path->name);
 126                        path->panel = NULL;
 127                        break;
 128                }
 129        }
 130        mutex_unlock(&disp_lock);
 131}
 132EXPORT_SYMBOL_GPL(mmp_unregister_panel);
 133
 134/*
 135 * mmp_get_path - get path by name
 136 * @p: path name
 137 *
 138 * this function checks path name in path_list and return matching path
 139 * return NULL if no matching path
 140 */
 141struct mmp_path *mmp_get_path(const char *name)
 142{
 143        struct mmp_path *path;
 144        int found = 0;
 145
 146        mutex_lock(&disp_lock);
 147        list_for_each_entry(path, &path_list, node) {
 148                if (!strcmp(name, path->name)) {
 149                        found = 1;
 150                        break;
 151                }
 152        }
 153        mutex_unlock(&disp_lock);
 154
 155        return found ? path : NULL;
 156}
 157EXPORT_SYMBOL_GPL(mmp_get_path);
 158
 159/*
 160 * mmp_register_path - init and register path by path_info
 161 * @p: path info provided by display controller
 162 *
 163 * this function init by path info and register path to path_list
 164 * this function also try to connect path with panel by name
 165 */
 166struct mmp_path *mmp_register_path(struct mmp_path_info *info)
 167{
 168        int i;
 169        size_t size;
 170        struct mmp_path *path = NULL;
 171        struct mmp_panel *panel;
 172
 173        size = sizeof(struct mmp_path)
 174                + sizeof(struct mmp_overlay) * info->overlay_num;
 175        path = kzalloc(size, GFP_KERNEL);
 176        if (!path)
 177                return NULL;
 178
 179        /* path set */
 180        mutex_init(&path->access_ok);
 181        path->dev = info->dev;
 182        path->id = info->id;
 183        path->name = info->name;
 184        path->output_type = info->output_type;
 185        path->overlay_num = info->overlay_num;
 186        path->plat_data = info->plat_data;
 187        path->ops.set_mode = info->set_mode;
 188
 189        mutex_lock(&disp_lock);
 190        /* get panel */
 191        list_for_each_entry(panel, &panel_list, node) {
 192                if (!strcmp(info->name, panel->plat_path_name)) {
 193                        dev_info(path->dev, "get panel %s\n", panel->name);
 194                        path->panel = panel;
 195                        break;
 196                }
 197        }
 198
 199        dev_info(path->dev, "register %s, overlay_num %d\n",
 200                        path->name, path->overlay_num);
 201
 202        /* default op set: if already set by driver, never cover it */
 203        if (!path->ops.check_status)
 204                path->ops.check_status = path_check_status;
 205        if (!path->ops.get_overlay)
 206                path->ops.get_overlay = path_get_overlay;
 207        if (!path->ops.get_modelist)
 208                path->ops.get_modelist = path_get_modelist;
 209
 210        /* step3: init overlays */
 211        for (i = 0; i < path->overlay_num; i++) {
 212                path->overlays[i].path = path;
 213                path->overlays[i].id = i;
 214                mutex_init(&path->overlays[i].access_ok);
 215                path->overlays[i].ops = info->overlay_ops;
 216        }
 217
 218        /* add to pathlist */
 219        list_add_tail(&path->node, &path_list);
 220
 221        mutex_unlock(&disp_lock);
 222        return path;
 223}
 224EXPORT_SYMBOL_GPL(mmp_register_path);
 225
 226/*
 227 * mmp_unregister_path - unregister and destroy path
 228 * @p: path to be destroyed.
 229 *
 230 * this function registers path and destroys it.
 231 */
 232void mmp_unregister_path(struct mmp_path *path)
 233{
 234        int i;
 235
 236        if (!path)
 237                return;
 238
 239        mutex_lock(&disp_lock);
 240        /* del from pathlist */
 241        list_del(&path->node);
 242
 243        /* deinit overlays */
 244        for (i = 0; i < path->overlay_num; i++)
 245                mutex_destroy(&path->overlays[i].access_ok);
 246
 247        mutex_destroy(&path->access_ok);
 248
 249        kfree(path);
 250        mutex_unlock(&disp_lock);
 251}
 252EXPORT_SYMBOL_GPL(mmp_unregister_path);
 253
 254MODULE_AUTHOR("Zhou Zhu <zzhu3@marvell.com>");
 255MODULE_DESCRIPTION("Marvell MMP display framework");
 256MODULE_LICENSE("GPL");
 257