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_get_sync(mic->dev);
 272        if (ret < 0) {
 273                pm_runtime_put_noidle(mic->dev);
 274                goto unlock;
 275        }
 276
 277        mic_set_path(mic, 1);
 278
 279        ret = mic_sw_reset(mic);
 280        if (ret) {
 281                DRM_DEV_ERROR(mic->dev, "Failed to reset\n");
 282                goto turn_off;
 283        }
 284
 285        if (!mic->i80_mode)
 286                mic_set_porch_timing(mic);
 287        mic_set_img_size(mic);
 288        mic_set_output_timing(mic);
 289        mic_set_reg_on(mic, 1);
 290        mic->enabled = 1;
 291        mutex_unlock(&mic_mutex);
 292
 293        return;
 294
 295turn_off:
 296        pm_runtime_put(mic->dev);
 297unlock:
 298        mutex_unlock(&mic_mutex);
 299}
 300
 301static void mic_enable(struct drm_bridge *bridge) { }
 302
 303static const struct drm_bridge_funcs mic_bridge_funcs = {
 304        .disable = mic_disable,
 305        .post_disable = mic_post_disable,
 306        .mode_set = mic_mode_set,
 307        .pre_enable = mic_pre_enable,
 308        .enable = mic_enable,
 309};
 310
 311static int exynos_mic_bind(struct device *dev, struct device *master,
 312                           void *data)
 313{
 314        struct exynos_mic *mic = dev_get_drvdata(dev);
 315
 316        mic->bridge.driver_private = mic;
 317
 318        return 0;
 319}
 320
 321static void exynos_mic_unbind(struct device *dev, struct device *master,
 322                              void *data)
 323{
 324        struct exynos_mic *mic = dev_get_drvdata(dev);
 325
 326        mutex_lock(&mic_mutex);
 327        if (!mic->enabled)
 328                goto already_disabled;
 329
 330        pm_runtime_put(mic->dev);
 331
 332already_disabled:
 333        mutex_unlock(&mic_mutex);
 334}
 335
 336static const struct component_ops exynos_mic_component_ops = {
 337        .bind   = exynos_mic_bind,
 338        .unbind = exynos_mic_unbind,
 339};
 340
 341#ifdef CONFIG_PM
 342static int exynos_mic_suspend(struct device *dev)
 343{
 344        struct exynos_mic *mic = dev_get_drvdata(dev);
 345        int i;
 346
 347        for (i = NUM_CLKS - 1; i > -1; i--)
 348                clk_disable_unprepare(mic->clks[i]);
 349
 350        return 0;
 351}
 352
 353static int exynos_mic_resume(struct device *dev)
 354{
 355        struct exynos_mic *mic = dev_get_drvdata(dev);
 356        int ret, i;
 357
 358        for (i = 0; i < NUM_CLKS; i++) {
 359                ret = clk_prepare_enable(mic->clks[i]);
 360                if (ret < 0) {
 361                        DRM_DEV_ERROR(dev, "Failed to enable clock (%s)\n",
 362                                      clk_names[i]);
 363                        while (--i > -1)
 364                                clk_disable_unprepare(mic->clks[i]);
 365                        return ret;
 366                }
 367        }
 368        return 0;
 369}
 370#endif
 371
 372static const struct dev_pm_ops exynos_mic_pm_ops = {
 373        SET_RUNTIME_PM_OPS(exynos_mic_suspend, exynos_mic_resume, NULL)
 374        SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
 375                                pm_runtime_force_resume)
 376};
 377
 378static int exynos_mic_probe(struct platform_device *pdev)
 379{
 380        struct device *dev = &pdev->dev;
 381        struct exynos_mic *mic;
 382        struct resource res;
 383        int ret, i;
 384
 385        mic = devm_kzalloc(dev, sizeof(*mic), GFP_KERNEL);
 386        if (!mic) {
 387                DRM_DEV_ERROR(dev,
 388                              "mic: Failed to allocate memory for MIC object\n");
 389                ret = -ENOMEM;
 390                goto err;
 391        }
 392
 393        mic->dev = dev;
 394
 395        ret = of_address_to_resource(dev->of_node, 0, &res);
 396        if (ret) {
 397                DRM_DEV_ERROR(dev, "mic: Failed to get mem region for MIC\n");
 398                goto err;
 399        }
 400        mic->reg = devm_ioremap(dev, res.start, resource_size(&res));
 401        if (!mic->reg) {
 402                DRM_DEV_ERROR(dev, "mic: Failed to remap for MIC\n");
 403                ret = -ENOMEM;
 404                goto err;
 405        }
 406
 407        mic->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
 408                                                        "samsung,disp-syscon");
 409        if (IS_ERR(mic->sysreg)) {
 410                DRM_DEV_ERROR(dev, "mic: Failed to get system register.\n");
 411                ret = PTR_ERR(mic->sysreg);
 412                goto err;
 413        }
 414
 415        for (i = 0; i < NUM_CLKS; i++) {
 416                mic->clks[i] = devm_clk_get(dev, clk_names[i]);
 417                if (IS_ERR(mic->clks[i])) {
 418                        DRM_DEV_ERROR(dev, "mic: Failed to get clock (%s)\n",
 419                                      clk_names[i]);
 420                        ret = PTR_ERR(mic->clks[i]);
 421                        goto err;
 422                }
 423        }
 424
 425        platform_set_drvdata(pdev, mic);
 426
 427        mic->bridge.funcs = &mic_bridge_funcs;
 428        mic->bridge.of_node = dev->of_node;
 429
 430        drm_bridge_add(&mic->bridge);
 431
 432        pm_runtime_enable(dev);
 433
 434        ret = component_add(dev, &exynos_mic_component_ops);
 435        if (ret)
 436                goto err_pm;
 437
 438        DRM_DEV_DEBUG_KMS(dev, "MIC has been probed\n");
 439
 440        return 0;
 441
 442err_pm:
 443        pm_runtime_disable(dev);
 444err:
 445        return ret;
 446}
 447
 448static int exynos_mic_remove(struct platform_device *pdev)
 449{
 450        struct exynos_mic *mic = platform_get_drvdata(pdev);
 451
 452        component_del(&pdev->dev, &exynos_mic_component_ops);
 453        pm_runtime_disable(&pdev->dev);
 454
 455        drm_bridge_remove(&mic->bridge);
 456
 457        return 0;
 458}
 459
 460static const struct of_device_id exynos_mic_of_match[] = {
 461        { .compatible = "samsung,exynos5433-mic" },
 462        { }
 463};
 464MODULE_DEVICE_TABLE(of, exynos_mic_of_match);
 465
 466struct platform_driver mic_driver = {
 467        .probe          = exynos_mic_probe,
 468        .remove         = exynos_mic_remove,
 469        .driver         = {
 470                .name   = "exynos-mic",
 471                .pm     = &exynos_mic_pm_ops,
 472                .owner  = THIS_MODULE,
 473                .of_match_table = exynos_mic_of_match,
 474        },
 475};
 476