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