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 86 enum { 87 ENDPOINT_DECON_NODE, 88 ENDPOINT_DSI_NODE, 89 NUM_ENDPOINTS 90 }; 91 92 static char *clk_names[] = { "pclk_mic0", "sclk_rgb_vclk_to_mic0" }; 93 #define NUM_CLKS ARRAY_SIZE(clk_names) 94 static DEFINE_MUTEX(mic_mutex); 95 96 struct 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 110 static 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 136 static 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 154 static 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 178 static 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 189 static 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 211 static 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 230 static 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 248 exit: 249 of_node_put(endpoint); 250 return remote_node; 251 } 252 253 static 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 302 exit: 303 while (--j > -1) 304 of_node_put(nodes[j]); 305 306 return ret; 307 } 308 309 void mic_disable(struct drm_bridge *bridge) { } 310 311 void 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 327 already_disabled: 328 mutex_unlock(&mic_mutex); 329 } 330 331 void 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 367 turn_off_clks: 368 while (--i > -1) 369 clk_disable_unprepare(mic->clks[i]); 370 already_enabled: 371 mutex_unlock(&mic_mutex); 372 } 373 374 void mic_enable(struct drm_bridge *bridge) { } 375 376 void 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 388 already_disabled: 389 mutex_unlock(&mic_mutex); 390 } 391 392 struct 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 399 int 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 459 err: 460 return ret; 461 } 462 463 static 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 476 static const struct of_device_id exynos_mic_of_match[] = { 477 { .compatible = "samsung,exynos5433-mic" }, 478 { } 479 }; 480 MODULE_DEVICE_TABLE(of, exynos_mic_of_match); 481 482 struct 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