linux/drivers/gpu/drm/exynos/exynos_drm_mic.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2015 Samsung Electronics Co.Ltd
   4 * Authors:
   5 *      Hyungwon Hwang <human.hwang@samsung.com>
   6 */
   7
   8#include <linux/clk.h>
   9#include <linux/component.h>
  10#include <linux/delay.h>
  11#include <linux/mfd/syscon.h>
  12#include <linux/module.h>
  13#include <linux/mutex.h>
  14#include <linux/of.h>
  15#include <linux/of_address.h>
  16#include <linux/of_graph.h>
  17#include <linux/platform_device.h>
  18#include <linux/pm_runtime.h>
  19#include <linux/regmap.h>
  20
  21#include <video/of_videomode.h>
  22#include <video/videomode.h>
  23
  24#include <drm/drm_bridge.h>
  25#include <drm/drm_encoder.h>
  26#include <drm/drm_print.h>
  27
  28#include "exynos_drm_drv.h"
  29
  30/* Sysreg registers for MIC */
  31#define DSD_CFG_MUX     0x1004
  32#define MIC0_RGB_MUX    (1 << 0)
  33#define MIC0_I80_MUX    (1 << 1)
  34#define MIC0_ON_MUX     (1 << 5)
  35
  36/* MIC registers */
  37#define MIC_OP                          0x0
  38#define MIC_IP_VER                      0x0004
  39#define MIC_V_TIMING_0                  0x0008
  40#define MIC_V_TIMING_1                  0x000C
  41#define MIC_IMG_SIZE                    0x0010
  42#define MIC_INPUT_TIMING_0              0x0014
  43#define MIC_INPUT_TIMING_1              0x0018
  44#define MIC_2D_OUTPUT_TIMING_0          0x001C
  45#define MIC_2D_OUTPUT_TIMING_1          0x0020
  46#define MIC_2D_OUTPUT_TIMING_2          0x0024
  47#define MIC_3D_OUTPUT_TIMING_0          0x0028
  48#define MIC_3D_OUTPUT_TIMING_1          0x002C
  49#define MIC_3D_OUTPUT_TIMING_2          0x0030
  50#define MIC_CORE_PARA_0                 0x0034
  51#define MIC_CORE_PARA_1                 0x0038
  52#define MIC_CTC_CTRL                    0x0040
  53#define MIC_RD_DATA                     0x0044
  54
  55#define MIC_UPD_REG                     (1 << 31)
  56#define MIC_ON_REG                      (1 << 30)
  57#define MIC_TD_ON_REG                   (1 << 29)
  58#define MIC_BS_CHG_OUT                  (1 << 16)
  59#define MIC_VIDEO_TYPE(x)               (((x) & 0xf) << 12)
  60#define MIC_PSR_EN                      (1 << 5)
  61#define MIC_SW_RST                      (1 << 4)
  62#define MIC_ALL_RST                     (1 << 3)
  63#define MIC_CORE_VER_CONTROL            (1 << 2)
  64#define MIC_MODE_SEL_COMMAND_MODE       (1 << 1)
  65#define MIC_MODE_SEL_MASK               (1 << 1)
  66#define MIC_CORE_EN                     (1 << 0)
  67
  68#define MIC_V_PULSE_WIDTH(x)            (((x) & 0x3fff) << 16)
  69#define MIC_V_PERIOD_LINE(x)            ((x) & 0x3fff)
  70
  71#define MIC_VBP_SIZE(x)                 (((x) & 0x3fff) << 16)
  72#define MIC_VFP_SIZE(x)                 ((x) & 0x3fff)
  73
  74#define MIC_IMG_V_SIZE(x)               (((x) & 0x3fff) << 16)
  75#define MIC_IMG_H_SIZE(x)               ((x) & 0x3fff)
  76
  77#define MIC_H_PULSE_WIDTH_IN(x)         (((x) & 0x3fff) << 16)
  78#define MIC_H_PERIOD_PIXEL_IN(x)        ((x) & 0x3fff)
  79
  80#define MIC_HBP_SIZE_IN(x)              (((x) & 0x3fff) << 16)
  81#define MIC_HFP_SIZE_IN(x)              ((x) & 0x3fff)
  82
  83#define MIC_H_PULSE_WIDTH_2D(x)         (((x) & 0x3fff) << 16)
  84#define MIC_H_PERIOD_PIXEL_2D(x)        ((x) & 0x3fff)
  85
  86#define MIC_HBP_SIZE_2D(x)              (((x) & 0x3fff) << 16)
  87#define MIC_HFP_SIZE_2D(x)              ((x) & 0x3fff)
  88
  89#define MIC_BS_SIZE_2D(x)       ((x) & 0x3fff)
  90
  91static const char *const clk_names[] = { "pclk_mic0", "sclk_rgb_vclk_to_mic0" };
  92#define NUM_CLKS                ARRAY_SIZE(clk_names)
  93static DEFINE_MUTEX(mic_mutex);
  94
  95struct exynos_mic {
  96        struct device *dev;
  97        void __iomem *reg;
  98        struct regmap *sysreg;
  99        struct clk *clks[NUM_CLKS];
 100
 101        bool i80_mode;
 102        struct videomode vm;
 103        struct drm_encoder *encoder;
 104        struct drm_bridge bridge;
 105
 106        bool enabled;
 107};
 108
 109static void mic_set_path(struct exynos_mic *mic, bool enable)
 110{
 111        int ret;
 112        unsigned int val;
 113
 114        ret = regmap_read(mic->sysreg, DSD_CFG_MUX, &val);
 115        if (ret) {
 116                DRM_DEV_ERROR(mic->dev,
 117                              "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        ret = regmap_write(mic->sysreg, DSD_CFG_MUX, val);
 132        if (ret)
 133                DRM_DEV_ERROR(mic->dev,
 134                              "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_DEV_DEBUG(mic->dev, "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 void mic_disable(struct drm_bridge *bridge) { }
 232
 233static void mic_post_disable(struct drm_bridge *bridge)
 234{
 235        struct exynos_mic *mic = bridge->driver_private;
 236
 237        mutex_lock(&mic_mutex);
 238        if (!mic->enabled)
 239                goto already_disabled;
 240
 241        mic_set_path(mic, 0);
 242
 243        pm_runtime_put(mic->dev);
 244        mic->enabled = 0;
 245
 246already_disabled:
 247        mutex_unlock(&mic_mutex);
 248}
 249
 250static void mic_mode_set(struct drm_bridge *bridge,
 251                         const struct drm_display_mode *mode,
 252                         const struct drm_display_mode *adjusted_mode)
 253{
 254        struct exynos_mic *mic = bridge->driver_private;
 255
 256        mutex_lock(&mic_mutex);
 257        drm_display_mode_to_videomode(mode, &mic->vm);
 258        mic->i80_mode = to_exynos_crtc(bridge->encoder->crtc)->i80_mode;
 259        mutex_unlock(&mic_mutex);
 260}
 261
 262static void mic_pre_enable(struct drm_bridge *bridge)
 263{
 264        struct exynos_mic *mic = bridge->driver_private;
 265        int ret;
 266
 267        mutex_lock(&mic_mutex);
 268        if (mic->enabled)
 269                goto unlock;
 270
 271        ret = pm_runtime_resume_and_get(mic->dev);
 272        if (ret < 0)
 273                goto unlock;
 274
 275        mic_set_path(mic, 1);
 276
 277        ret = mic_sw_reset(mic);
 278        if (ret) {
 279                DRM_DEV_ERROR(mic->dev, "Failed to reset\n");
 280                goto turn_off;
 281        }
 282
 283        if (!mic->i80_mode)
 284                mic_set_porch_timing(mic);
 285        mic_set_img_size(mic);
 286        mic_set_output_timing(mic);
 287        mic_set_reg_on(mic, 1);
 288        mic->enabled = 1;
 289        mutex_unlock(&mic_mutex);
 290
 291        return;
 292
 293turn_off:
 294        pm_runtime_put(mic->dev);
 295unlock:
 296        mutex_unlock(&mic_mutex);
 297}
 298
 299static void mic_enable(struct drm_bridge *bridge) { }
 300
 301static const struct drm_bridge_funcs mic_bridge_funcs = {
 302        .disable = mic_disable,
 303        .post_disable = mic_post_disable,
 304        .mode_set = mic_mode_set,
 305        .pre_enable = mic_pre_enable,
 306        .enable = mic_enable,
 307};
 308
 309static int exynos_mic_bind(struct device *dev, struct device *master,
 310                           void *data)
 311{
 312        struct exynos_mic *mic = dev_get_drvdata(dev);
 313
 314        mic->bridge.driver_private = mic;
 315
 316        return 0;
 317}
 318
 319static void exynos_mic_unbind(struct device *dev, struct device *master,
 320                              void *data)
 321{
 322        struct exynos_mic *mic = dev_get_drvdata(dev);
 323
 324        mutex_lock(&mic_mutex);
 325        if (!mic->enabled)
 326                goto already_disabled;
 327
 328        pm_runtime_put(mic->dev);
 329
 330already_disabled:
 331        mutex_unlock(&mic_mutex);
 332}
 333
 334static const struct component_ops exynos_mic_component_ops = {
 335        .bind   = exynos_mic_bind,
 336        .unbind = exynos_mic_unbind,
 337};
 338
 339#ifdef CONFIG_PM
 340static int exynos_mic_suspend(struct device *dev)
 341{
 342        struct exynos_mic *mic = dev_get_drvdata(dev);
 343        int i;
 344
 345        for (i = NUM_CLKS - 1; i > -1; i--)
 346                clk_disable_unprepare(mic->clks[i]);
 347
 348        return 0;
 349}
 350
 351static int exynos_mic_resume(struct device *dev)
 352{
 353        struct exynos_mic *mic = dev_get_drvdata(dev);
 354        int ret, i;
 355
 356        for (i = 0; i < NUM_CLKS; i++) {
 357                ret = clk_prepare_enable(mic->clks[i]);
 358                if (ret < 0) {
 359                        DRM_DEV_ERROR(dev, "Failed to enable clock (%s)\n",
 360                                      clk_names[i]);
 361                        while (--i > -1)
 362                                clk_disable_unprepare(mic->clks[i]);
 363                        return ret;
 364                }
 365        }
 366        return 0;
 367}
 368#endif
 369
 370static const struct dev_pm_ops exynos_mic_pm_ops = {
 371        SET_RUNTIME_PM_OPS(exynos_mic_suspend, exynos_mic_resume, NULL)
 372        SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
 373                                pm_runtime_force_resume)
 374};
 375
 376static int exynos_mic_probe(struct platform_device *pdev)
 377{
 378        struct device *dev = &pdev->dev;
 379        struct exynos_mic *mic;
 380        struct resource res;
 381        int ret, i;
 382
 383        mic = devm_kzalloc(dev, sizeof(*mic), GFP_KERNEL);
 384        if (!mic) {
 385                DRM_DEV_ERROR(dev,
 386                              "mic: Failed to allocate memory for MIC object\n");
 387                ret = -ENOMEM;
 388                goto err;
 389        }
 390
 391        mic->dev = dev;
 392
 393        ret = of_address_to_resource(dev->of_node, 0, &res);
 394        if (ret) {
 395                DRM_DEV_ERROR(dev, "mic: Failed to get mem region for MIC\n");
 396                goto err;
 397        }
 398        mic->reg = devm_ioremap(dev, res.start, resource_size(&res));
 399        if (!mic->reg) {
 400                DRM_DEV_ERROR(dev, "mic: Failed to remap for MIC\n");
 401                ret = -ENOMEM;
 402                goto err;
 403        }
 404
 405        mic->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
 406                                                        "samsung,disp-syscon");
 407        if (IS_ERR(mic->sysreg)) {
 408                DRM_DEV_ERROR(dev, "mic: Failed to get system register.\n");
 409                ret = PTR_ERR(mic->sysreg);
 410                goto err;
 411        }
 412
 413        for (i = 0; i < NUM_CLKS; i++) {
 414                mic->clks[i] = devm_clk_get(dev, clk_names[i]);
 415                if (IS_ERR(mic->clks[i])) {
 416                        DRM_DEV_ERROR(dev, "mic: Failed to get clock (%s)\n",
 417                                      clk_names[i]);
 418                        ret = PTR_ERR(mic->clks[i]);
 419                        goto err;
 420                }
 421        }
 422
 423        platform_set_drvdata(pdev, mic);
 424
 425        mic->bridge.funcs = &mic_bridge_funcs;
 426        mic->bridge.of_node = dev->of_node;
 427
 428        drm_bridge_add(&mic->bridge);
 429
 430        pm_runtime_enable(dev);
 431
 432        ret = component_add(dev, &exynos_mic_component_ops);
 433        if (ret)
 434                goto err_pm;
 435
 436        DRM_DEV_DEBUG_KMS(dev, "MIC has been probed\n");
 437
 438        return 0;
 439
 440err_pm:
 441        pm_runtime_disable(dev);
 442err:
 443        return ret;
 444}
 445
 446static int exynos_mic_remove(struct platform_device *pdev)
 447{
 448        struct exynos_mic *mic = platform_get_drvdata(pdev);
 449
 450        component_del(&pdev->dev, &exynos_mic_component_ops);
 451        pm_runtime_disable(&pdev->dev);
 452
 453        drm_bridge_remove(&mic->bridge);
 454
 455        return 0;
 456}
 457
 458static const struct of_device_id exynos_mic_of_match[] = {
 459        { .compatible = "samsung,exynos5433-mic" },
 460        { }
 461};
 462MODULE_DEVICE_TABLE(of, exynos_mic_of_match);
 463
 464struct platform_driver mic_driver = {
 465        .probe          = exynos_mic_probe,
 466        .remove         = exynos_mic_remove,
 467        .driver         = {
 468                .name   = "exynos-mic",
 469                .pm     = &exynos_mic_pm_ops,
 470                .owner  = THIS_MODULE,
 471                .of_match_table = exynos_mic_of_match,
 472        },
 473};
 474