linux/drivers/gpu/drm/exynos/exynos_drm_mic.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2015 Samsung Electronics Co.Ltd
   3 * Authors:
   4 *      Hyungwon Hwang <human.hwang@samsung.com>
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundationr
   9 */
  10
  11#include <linux/platform_device.h>
  12#include <video/of_videomode.h>
  13#include <linux/of_address.h>
  14#include <video/videomode.h>
  15#include <linux/module.h>
  16#include <linux/delay.h>
  17#include <linux/mutex.h>
  18#include <linux/of.h>
  19#include <linux/of_graph.h>
  20#include <linux/clk.h>
  21#include <drm/drmP.h>
  22#include <linux/mfd/syscon.h>
  23#include <linux/regmap.h>
  24
  25/* Sysreg registers for MIC */
  26#define DSD_CFG_MUX     0x1004
  27#define MIC0_RGB_MUX    (1 << 0)
  28#define MIC0_I80_MUX    (1 << 1)
  29#define MIC0_ON_MUX     (1 << 5)
  30
  31/* MIC registers */
  32#define MIC_OP                          0x0
  33#define MIC_IP_VER                      0x0004
  34#define MIC_V_TIMING_0                  0x0008
  35#define MIC_V_TIMING_1                  0x000C
  36#define MIC_IMG_SIZE                    0x0010
  37#define MIC_INPUT_TIMING_0              0x0014
  38#define MIC_INPUT_TIMING_1              0x0018
  39#define MIC_2D_OUTPUT_TIMING_0          0x001C
  40#define MIC_2D_OUTPUT_TIMING_1          0x0020
  41#define MIC_2D_OUTPUT_TIMING_2          0x0024
  42#define MIC_3D_OUTPUT_TIMING_0          0x0028
  43#define MIC_3D_OUTPUT_TIMING_1          0x002C
  44#define MIC_3D_OUTPUT_TIMING_2          0x0030
  45#define MIC_CORE_PARA_0                 0x0034
  46#define MIC_CORE_PARA_1                 0x0038
  47#define MIC_CTC_CTRL                    0x0040
  48#define MIC_RD_DATA                     0x0044
  49
  50#define MIC_UPD_REG                     (1 << 31)
  51#define MIC_ON_REG                      (1 << 30)
  52#define MIC_TD_ON_REG                   (1 << 29)
  53#define MIC_BS_CHG_OUT                  (1 << 16)
  54#define MIC_VIDEO_TYPE(x)               (((x) & 0xf) << 12)
  55#define MIC_PSR_EN                      (1 << 5)
  56#define MIC_SW_RST                      (1 << 4)
  57#define MIC_ALL_RST                     (1 << 3)
  58#define MIC_CORE_VER_CONTROL            (1 << 2)
  59#define MIC_MODE_SEL_COMMAND_MODE       (1 << 1)
  60#define MIC_MODE_SEL_MASK               (1 << 1)
  61#define MIC_CORE_EN                     (1 << 0)
  62
  63#define MIC_V_PULSE_WIDTH(x)            (((x) & 0x3fff) << 16)
  64#define MIC_V_PERIOD_LINE(x)            ((x) & 0x3fff)
  65
  66#define MIC_VBP_SIZE(x)                 (((x) & 0x3fff) << 16)
  67#define MIC_VFP_SIZE(x)                 ((x) & 0x3fff)
  68
  69#define MIC_IMG_V_SIZE(x)               (((x) & 0x3fff) << 16)
  70#define MIC_IMG_H_SIZE(x)               ((x) & 0x3fff)
  71
  72#define MIC_H_PULSE_WIDTH_IN(x)         (((x) & 0x3fff) << 16)
  73#define MIC_H_PERIOD_PIXEL_IN(x)        ((x) & 0x3fff)
  74
  75#define MIC_HBP_SIZE_IN(x)              (((x) & 0x3fff) << 16)
  76#define MIC_HFP_SIZE_IN(x)              ((x) & 0x3fff)
  77
  78#define MIC_H_PULSE_WIDTH_2D(x)         (((x) & 0x3fff) << 16)
  79#define MIC_H_PERIOD_PIXEL_2D(x)        ((x) & 0x3fff)
  80
  81#define MIC_HBP_SIZE_2D(x)              (((x) & 0x3fff) << 16)
  82#define MIC_HFP_SIZE_2D(x)              ((x) & 0x3fff)
  83
  84#define MIC_BS_SIZE_2D(x)       ((x) & 0x3fff)
  85
  86enum {
  87        ENDPOINT_DECON_NODE,
  88        ENDPOINT_DSI_NODE,
  89        NUM_ENDPOINTS
  90};
  91
  92static char *clk_names[] = { "pclk_mic0", "sclk_rgb_vclk_to_mic0" };
  93#define NUM_CLKS                ARRAY_SIZE(clk_names)
  94static DEFINE_MUTEX(mic_mutex);
  95
  96struct exynos_mic {
  97        struct device *dev;
  98        void __iomem *reg;
  99        struct regmap *sysreg;
 100        struct clk *clks[NUM_CLKS];
 101
 102        bool i80_mode;
 103        struct videomode vm;
 104        struct drm_encoder *encoder;
 105        struct drm_bridge bridge;
 106
 107        bool enabled;
 108};
 109
 110static void mic_set_path(struct exynos_mic *mic, bool enable)
 111{
 112        int ret;
 113        unsigned int val;
 114
 115        ret = regmap_read(mic->sysreg, DSD_CFG_MUX, &val);
 116        if (ret) {
 117                DRM_ERROR("mic: Failed to read system register\n");
 118                return;
 119        }
 120
 121        if (enable) {
 122                if (mic->i80_mode)
 123                        val |= MIC0_I80_MUX;
 124                else
 125                        val |= MIC0_RGB_MUX;
 126
 127                val |=  MIC0_ON_MUX;
 128        } else
 129                val &= ~(MIC0_RGB_MUX | MIC0_I80_MUX | MIC0_ON_MUX);
 130
 131        regmap_write(mic->sysreg, DSD_CFG_MUX, val);
 132        if (ret)
 133                DRM_ERROR("mic: Failed to read system register\n");
 134}
 135
 136static int mic_sw_reset(struct exynos_mic *mic)
 137{
 138        unsigned int retry = 100;
 139        int ret;
 140
 141        writel(MIC_SW_RST, mic->reg + MIC_OP);
 142
 143        while (retry-- > 0) {
 144                ret = readl(mic->reg + MIC_OP);
 145                if (!(ret & MIC_SW_RST))
 146                        return 0;
 147
 148                udelay(10);
 149        }
 150
 151        return -ETIMEDOUT;
 152}
 153
 154static void mic_set_porch_timing(struct exynos_mic *mic)
 155{
 156        struct videomode vm = mic->vm;
 157        u32 reg;
 158
 159        reg = MIC_V_PULSE_WIDTH(vm.vsync_len) +
 160                MIC_V_PERIOD_LINE(vm.vsync_len + vm.vactive +
 161                                vm.vback_porch + vm.vfront_porch);
 162        writel(reg, mic->reg + MIC_V_TIMING_0);
 163
 164        reg = MIC_VBP_SIZE(vm.vback_porch) +
 165                MIC_VFP_SIZE(vm.vfront_porch);
 166        writel(reg, mic->reg + MIC_V_TIMING_1);
 167
 168        reg = MIC_V_PULSE_WIDTH(vm.hsync_len) +
 169                MIC_V_PERIOD_LINE(vm.hsync_len + vm.hactive +
 170                                vm.hback_porch + vm.hfront_porch);
 171        writel(reg, mic->reg + MIC_INPUT_TIMING_0);
 172
 173        reg = MIC_VBP_SIZE(vm.hback_porch) +
 174                MIC_VFP_SIZE(vm.hfront_porch);
 175        writel(reg, mic->reg + MIC_INPUT_TIMING_1);
 176}
 177
 178static void mic_set_img_size(struct exynos_mic *mic)
 179{
 180        struct videomode *vm = &mic->vm;
 181        u32 reg;
 182
 183        reg = MIC_IMG_H_SIZE(vm->hactive) +
 184                MIC_IMG_V_SIZE(vm->vactive);
 185
 186        writel(reg, mic->reg + MIC_IMG_SIZE);
 187}
 188
 189static void mic_set_output_timing(struct exynos_mic *mic)
 190{
 191        struct videomode vm = mic->vm;
 192        u32 reg, bs_size_2d;
 193
 194        DRM_DEBUG("w: %u, h: %u\n", vm.hactive, vm.vactive);
 195        bs_size_2d = ((vm.hactive >> 2) << 1) + (vm.vactive % 4);
 196        reg = MIC_BS_SIZE_2D(bs_size_2d);
 197        writel(reg, mic->reg + MIC_2D_OUTPUT_TIMING_2);
 198
 199        if (!mic->i80_mode) {
 200                reg = MIC_H_PULSE_WIDTH_2D(vm.hsync_len) +
 201                        MIC_H_PERIOD_PIXEL_2D(vm.hsync_len + bs_size_2d +
 202                                        vm.hback_porch + vm.hfront_porch);
 203                writel(reg, mic->reg + MIC_2D_OUTPUT_TIMING_0);
 204
 205                reg = MIC_HBP_SIZE_2D(vm.hback_porch) +
 206                        MIC_H_PERIOD_PIXEL_2D(vm.hfront_porch);
 207                writel(reg, mic->reg + MIC_2D_OUTPUT_TIMING_1);
 208        }
 209}
 210
 211static void mic_set_reg_on(struct exynos_mic *mic, bool enable)
 212{
 213        u32 reg = readl(mic->reg + MIC_OP);
 214
 215        if (enable) {
 216                reg &= ~(MIC_MODE_SEL_MASK | MIC_CORE_VER_CONTROL | MIC_PSR_EN);
 217                reg |= (MIC_CORE_EN | MIC_BS_CHG_OUT | MIC_ON_REG);
 218
 219                reg  &= ~MIC_MODE_SEL_COMMAND_MODE;
 220                if (mic->i80_mode)
 221                        reg |= MIC_MODE_SEL_COMMAND_MODE;
 222        } else {
 223                reg &= ~MIC_CORE_EN;
 224        }
 225
 226        reg |= MIC_UPD_REG;
 227        writel(reg, mic->reg + MIC_OP);
 228}
 229
 230static struct device_node *get_remote_node(struct device_node *from, int reg)
 231{
 232        struct device_node *endpoint = NULL, *remote_node = NULL;
 233
 234        endpoint = of_graph_get_endpoint_by_regs(from, reg, -1);
 235        if (!endpoint) {
 236                DRM_ERROR("mic: Failed to find remote port from %s",
 237                                from->full_name);
 238                goto exit;
 239        }
 240
 241        remote_node = of_graph_get_remote_port_parent(endpoint);
 242        if (!remote_node) {
 243                DRM_ERROR("mic: Failed to find remote port parent from %s",
 244                                                        from->full_name);
 245                goto exit;
 246        }
 247
 248exit:
 249        of_node_put(endpoint);
 250        return remote_node;
 251}
 252
 253static int parse_dt(struct exynos_mic *mic)
 254{
 255        int ret = 0, i, j;
 256        struct device_node *remote_node;
 257        struct device_node *nodes[3];
 258
 259        /*
 260         * The order of endpoints does matter.
 261         * The first node must be for decon and the second one must be for dsi.
 262         */
 263        for (i = 0, j = 0; i < NUM_ENDPOINTS; i++) {
 264                remote_node = get_remote_node(mic->dev->of_node, i);
 265                if (!remote_node) {
 266                        ret = -EPIPE;
 267                        goto exit;
 268                }
 269                nodes[j++] = remote_node;
 270
 271                switch (i) {
 272                case ENDPOINT_DECON_NODE:
 273                        /* decon node */
 274                        if (of_get_child_by_name(remote_node,
 275                                                "i80-if-timings"))
 276                                mic->i80_mode = 1;
 277
 278                        break;
 279                case ENDPOINT_DSI_NODE:
 280                        /* panel node */
 281                        remote_node = get_remote_node(remote_node, 1);
 282                        if (!remote_node) {
 283                                ret = -EPIPE;
 284                                goto exit;
 285                        }
 286                        nodes[j++] = remote_node;
 287
 288                        ret = of_get_videomode(remote_node,
 289                                                        &mic->vm, 0);
 290                        if (ret) {
 291                                DRM_ERROR("mic: failed to get videomode");
 292                                goto exit;
 293                        }
 294
 295                        break;
 296                default:
 297                        DRM_ERROR("mic: Unknown endpoint from MIC");
 298                        break;
 299                }
 300        }
 301
 302exit:
 303        while (--j > -1)
 304                of_node_put(nodes[j]);
 305
 306        return ret;
 307}
 308
 309void mic_disable(struct drm_bridge *bridge) { }
 310
 311void mic_post_disable(struct drm_bridge *bridge)
 312{
 313        struct exynos_mic *mic = bridge->driver_private;
 314        int i;
 315
 316        mutex_lock(&mic_mutex);
 317        if (!mic->enabled)
 318                goto already_disabled;
 319
 320        mic_set_path(mic, 0);
 321
 322        for (i = NUM_CLKS - 1; i > -1; i--)
 323                clk_disable_unprepare(mic->clks[i]);
 324
 325        mic->enabled = 0;
 326
 327already_disabled:
 328        mutex_unlock(&mic_mutex);
 329}
 330
 331void mic_pre_enable(struct drm_bridge *bridge)
 332{
 333        struct exynos_mic *mic = bridge->driver_private;
 334        int ret, i;
 335
 336        mutex_lock(&mic_mutex);
 337        if (mic->enabled)
 338                goto already_enabled;
 339
 340        for (i = 0; i < NUM_CLKS; i++) {
 341                ret = clk_prepare_enable(mic->clks[i]);
 342                if (ret < 0) {
 343                        DRM_ERROR("Failed to enable clock (%s)\n",
 344                                                        clk_names[i]);
 345                        goto turn_off_clks;
 346                }
 347        }
 348
 349        mic_set_path(mic, 1);
 350
 351        ret = mic_sw_reset(mic);
 352        if (ret) {
 353                DRM_ERROR("Failed to reset\n");
 354                goto turn_off_clks;
 355        }
 356
 357        if (!mic->i80_mode)
 358                mic_set_porch_timing(mic);
 359        mic_set_img_size(mic);
 360        mic_set_output_timing(mic);
 361        mic_set_reg_on(mic, 1);
 362        mic->enabled = 1;
 363        mutex_unlock(&mic_mutex);
 364
 365        return;
 366
 367turn_off_clks:
 368        while (--i > -1)
 369                clk_disable_unprepare(mic->clks[i]);
 370already_enabled:
 371        mutex_unlock(&mic_mutex);
 372}
 373
 374void mic_enable(struct drm_bridge *bridge) { }
 375
 376void mic_destroy(struct drm_bridge *bridge)
 377{
 378        struct exynos_mic *mic = bridge->driver_private;
 379        int i;
 380
 381        mutex_lock(&mic_mutex);
 382        if (!mic->enabled)
 383                goto already_disabled;
 384
 385        for (i = NUM_CLKS - 1; i > -1; i--)
 386                clk_disable_unprepare(mic->clks[i]);
 387
 388already_disabled:
 389        mutex_unlock(&mic_mutex);
 390}
 391
 392struct drm_bridge_funcs mic_bridge_funcs = {
 393        .disable = mic_disable,
 394        .post_disable = mic_post_disable,
 395        .pre_enable = mic_pre_enable,
 396        .enable = mic_enable,
 397};
 398
 399int exynos_mic_probe(struct platform_device *pdev)
 400{
 401        struct device *dev = &pdev->dev;
 402        struct exynos_mic *mic;
 403        struct resource res;
 404        int ret, i;
 405
 406        mic = devm_kzalloc(dev, sizeof(*mic), GFP_KERNEL);
 407        if (!mic) {
 408                DRM_ERROR("mic: Failed to allocate memory for MIC object\n");
 409                ret = -ENOMEM;
 410                goto err;
 411        }
 412
 413        mic->dev = dev;
 414
 415        ret = parse_dt(mic);
 416        if (ret)
 417                goto err;
 418
 419        ret = of_address_to_resource(dev->of_node, 0, &res);
 420        if (ret) {
 421                DRM_ERROR("mic: Failed to get mem region for MIC\n");
 422                goto err;
 423        }
 424        mic->reg = devm_ioremap(dev, res.start, resource_size(&res));
 425        if (!mic->reg) {
 426                DRM_ERROR("mic: Failed to remap for MIC\n");
 427                ret = -ENOMEM;
 428                goto err;
 429        }
 430
 431        mic->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
 432                                                        "samsung,disp-syscon");
 433        if (IS_ERR(mic->sysreg)) {
 434                DRM_ERROR("mic: Failed to get system register.\n");
 435                goto err;
 436        }
 437
 438        mic->bridge.funcs = &mic_bridge_funcs;
 439        mic->bridge.of_node = dev->of_node;
 440        mic->bridge.driver_private = mic;
 441        ret = drm_bridge_add(&mic->bridge);
 442        if (ret) {
 443                DRM_ERROR("mic: Failed to add MIC to the global bridge list\n");
 444                goto err;
 445        }
 446
 447        for (i = 0; i < NUM_CLKS; i++) {
 448                mic->clks[i] = of_clk_get_by_name(dev->of_node, clk_names[i]);
 449                if (IS_ERR(mic->clks[i])) {
 450                        DRM_ERROR("mic: Failed to get clock (%s)\n",
 451                                                                clk_names[i]);
 452                        ret = PTR_ERR(mic->clks[i]);
 453                        goto err;
 454                }
 455        }
 456
 457        DRM_DEBUG_KMS("MIC has been probed\n");
 458
 459err:
 460        return ret;
 461}
 462
 463static int exynos_mic_remove(struct platform_device *pdev)
 464{
 465        struct exynos_mic *mic = platform_get_drvdata(pdev);
 466        int i;
 467
 468        drm_bridge_remove(&mic->bridge);
 469
 470        for (i = NUM_CLKS - 1; i > -1; i--)
 471                clk_put(mic->clks[i]);
 472
 473        return 0;
 474}
 475
 476static const struct of_device_id exynos_mic_of_match[] = {
 477        { .compatible = "samsung,exynos5433-mic" },
 478        { }
 479};
 480MODULE_DEVICE_TABLE(of, exynos_mic_of_match);
 481
 482struct platform_driver mic_driver = {
 483        .probe          = exynos_mic_probe,
 484        .remove         = exynos_mic_remove,
 485        .driver         = {
 486                .name   = "exynos-mic",
 487                .owner  = THIS_MODULE,
 488                .of_match_table = exynos_mic_of_match,
 489        },
 490};
 491