| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (C) 2012 Avionic Design GmbH |
|---|
| 3 | 4 | * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. |
|---|
| 4 | | - * |
|---|
| 5 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 6 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 7 | | - * published by the Free Software Foundation. |
|---|
| 8 | 5 | */ |
|---|
| 9 | 6 | |
|---|
| 10 | 7 | #include <linux/clk.h> |
|---|
| 11 | 8 | #include <linux/debugfs.h> |
|---|
| 12 | | -#include <linux/gpio.h> |
|---|
| 9 | +#include <linux/delay.h> |
|---|
| 13 | 10 | #include <linux/hdmi.h> |
|---|
| 11 | +#include <linux/math64.h> |
|---|
| 12 | +#include <linux/module.h> |
|---|
| 14 | 13 | #include <linux/of_device.h> |
|---|
| 15 | 14 | #include <linux/pm_runtime.h> |
|---|
| 16 | 15 | #include <linux/regulator/consumer.h> |
|---|
| .. | .. |
|---|
| 18 | 17 | |
|---|
| 19 | 18 | #include <drm/drm_atomic_helper.h> |
|---|
| 20 | 19 | #include <drm/drm_crtc.h> |
|---|
| 21 | | -#include <drm/drm_crtc_helper.h> |
|---|
| 20 | +#include <drm/drm_debugfs.h> |
|---|
| 21 | +#include <drm/drm_file.h> |
|---|
| 22 | +#include <drm/drm_fourcc.h> |
|---|
| 23 | +#include <drm/drm_probe_helper.h> |
|---|
| 24 | +#include <drm/drm_simple_kms_helper.h> |
|---|
| 22 | 25 | |
|---|
| 23 | | -#include <sound/hda_verbs.h> |
|---|
| 24 | | - |
|---|
| 25 | | -#include <media/cec-notifier.h> |
|---|
| 26 | | - |
|---|
| 26 | +#include "hda.h" |
|---|
| 27 | 27 | #include "hdmi.h" |
|---|
| 28 | 28 | #include "drm.h" |
|---|
| 29 | 29 | #include "dc.h" |
|---|
| .. | .. |
|---|
| 71 | 71 | const struct tegra_hdmi_config *config; |
|---|
| 72 | 72 | |
|---|
| 73 | 73 | unsigned int audio_source; |
|---|
| 74 | | - unsigned int audio_sample_rate; |
|---|
| 75 | | - unsigned int audio_channels; |
|---|
| 74 | + struct tegra_hda_format format; |
|---|
| 76 | 75 | |
|---|
| 77 | 76 | unsigned int pixel_clock; |
|---|
| 78 | 77 | bool stereo; |
|---|
| .. | .. |
|---|
| 119 | 118 | } |
|---|
| 120 | 119 | |
|---|
| 121 | 120 | struct tegra_hdmi_audio_config { |
|---|
| 122 | | - unsigned int pclk; |
|---|
| 123 | 121 | unsigned int n; |
|---|
| 124 | 122 | unsigned int cts; |
|---|
| 125 | 123 | unsigned int aval; |
|---|
| 126 | | -}; |
|---|
| 127 | | - |
|---|
| 128 | | -static const struct tegra_hdmi_audio_config tegra_hdmi_audio_32k[] = { |
|---|
| 129 | | - { 25200000, 4096, 25200, 24000 }, |
|---|
| 130 | | - { 27000000, 4096, 27000, 24000 }, |
|---|
| 131 | | - { 74250000, 4096, 74250, 24000 }, |
|---|
| 132 | | - { 148500000, 4096, 148500, 24000 }, |
|---|
| 133 | | - { 0, 0, 0, 0 }, |
|---|
| 134 | | -}; |
|---|
| 135 | | - |
|---|
| 136 | | -static const struct tegra_hdmi_audio_config tegra_hdmi_audio_44_1k[] = { |
|---|
| 137 | | - { 25200000, 5880, 26250, 25000 }, |
|---|
| 138 | | - { 27000000, 5880, 28125, 25000 }, |
|---|
| 139 | | - { 74250000, 4704, 61875, 20000 }, |
|---|
| 140 | | - { 148500000, 4704, 123750, 20000 }, |
|---|
| 141 | | - { 0, 0, 0, 0 }, |
|---|
| 142 | | -}; |
|---|
| 143 | | - |
|---|
| 144 | | -static const struct tegra_hdmi_audio_config tegra_hdmi_audio_48k[] = { |
|---|
| 145 | | - { 25200000, 6144, 25200, 24000 }, |
|---|
| 146 | | - { 27000000, 6144, 27000, 24000 }, |
|---|
| 147 | | - { 74250000, 6144, 74250, 24000 }, |
|---|
| 148 | | - { 148500000, 6144, 148500, 24000 }, |
|---|
| 149 | | - { 0, 0, 0, 0 }, |
|---|
| 150 | | -}; |
|---|
| 151 | | - |
|---|
| 152 | | -static const struct tegra_hdmi_audio_config tegra_hdmi_audio_88_2k[] = { |
|---|
| 153 | | - { 25200000, 11760, 26250, 25000 }, |
|---|
| 154 | | - { 27000000, 11760, 28125, 25000 }, |
|---|
| 155 | | - { 74250000, 9408, 61875, 20000 }, |
|---|
| 156 | | - { 148500000, 9408, 123750, 20000 }, |
|---|
| 157 | | - { 0, 0, 0, 0 }, |
|---|
| 158 | | -}; |
|---|
| 159 | | - |
|---|
| 160 | | -static const struct tegra_hdmi_audio_config tegra_hdmi_audio_96k[] = { |
|---|
| 161 | | - { 25200000, 12288, 25200, 24000 }, |
|---|
| 162 | | - { 27000000, 12288, 27000, 24000 }, |
|---|
| 163 | | - { 74250000, 12288, 74250, 24000 }, |
|---|
| 164 | | - { 148500000, 12288, 148500, 24000 }, |
|---|
| 165 | | - { 0, 0, 0, 0 }, |
|---|
| 166 | | -}; |
|---|
| 167 | | - |
|---|
| 168 | | -static const struct tegra_hdmi_audio_config tegra_hdmi_audio_176_4k[] = { |
|---|
| 169 | | - { 25200000, 23520, 26250, 25000 }, |
|---|
| 170 | | - { 27000000, 23520, 28125, 25000 }, |
|---|
| 171 | | - { 74250000, 18816, 61875, 20000 }, |
|---|
| 172 | | - { 148500000, 18816, 123750, 20000 }, |
|---|
| 173 | | - { 0, 0, 0, 0 }, |
|---|
| 174 | | -}; |
|---|
| 175 | | - |
|---|
| 176 | | -static const struct tegra_hdmi_audio_config tegra_hdmi_audio_192k[] = { |
|---|
| 177 | | - { 25200000, 24576, 25200, 24000 }, |
|---|
| 178 | | - { 27000000, 24576, 27000, 24000 }, |
|---|
| 179 | | - { 74250000, 24576, 74250, 24000 }, |
|---|
| 180 | | - { 148500000, 24576, 148500, 24000 }, |
|---|
| 181 | | - { 0, 0, 0, 0 }, |
|---|
| 182 | 124 | }; |
|---|
| 183 | 125 | |
|---|
| 184 | 126 | static const struct tmds_config tegra20_tmds_config[] = { |
|---|
| .. | .. |
|---|
| 418 | 360 | }, |
|---|
| 419 | 361 | }; |
|---|
| 420 | 362 | |
|---|
| 421 | | -static const struct tegra_hdmi_audio_config * |
|---|
| 422 | | -tegra_hdmi_get_audio_config(unsigned int sample_rate, unsigned int pclk) |
|---|
| 363 | +static int |
|---|
| 364 | +tegra_hdmi_get_audio_config(unsigned int audio_freq, unsigned int pix_clock, |
|---|
| 365 | + struct tegra_hdmi_audio_config *config) |
|---|
| 423 | 366 | { |
|---|
| 424 | | - const struct tegra_hdmi_audio_config *table; |
|---|
| 367 | + const unsigned int afreq = 128 * audio_freq; |
|---|
| 368 | + const unsigned int min_n = afreq / 1500; |
|---|
| 369 | + const unsigned int max_n = afreq / 300; |
|---|
| 370 | + const unsigned int ideal_n = afreq / 1000; |
|---|
| 371 | + int64_t min_err = (uint64_t)-1 >> 1; |
|---|
| 372 | + unsigned int min_delta = -1; |
|---|
| 373 | + int n; |
|---|
| 425 | 374 | |
|---|
| 426 | | - switch (sample_rate) { |
|---|
| 427 | | - case 32000: |
|---|
| 428 | | - table = tegra_hdmi_audio_32k; |
|---|
| 429 | | - break; |
|---|
| 375 | + memset(config, 0, sizeof(*config)); |
|---|
| 376 | + config->n = -1; |
|---|
| 430 | 377 | |
|---|
| 431 | | - case 44100: |
|---|
| 432 | | - table = tegra_hdmi_audio_44_1k; |
|---|
| 433 | | - break; |
|---|
| 378 | + for (n = min_n; n <= max_n; n++) { |
|---|
| 379 | + uint64_t cts_f, aval_f; |
|---|
| 380 | + unsigned int delta; |
|---|
| 381 | + int64_t cts, err; |
|---|
| 434 | 382 | |
|---|
| 435 | | - case 48000: |
|---|
| 436 | | - table = tegra_hdmi_audio_48k; |
|---|
| 437 | | - break; |
|---|
| 383 | + /* compute aval in 48.16 fixed point */ |
|---|
| 384 | + aval_f = ((int64_t)24000000 << 16) * n; |
|---|
| 385 | + do_div(aval_f, afreq); |
|---|
| 386 | + /* It should round without any rest */ |
|---|
| 387 | + if (aval_f & 0xFFFF) |
|---|
| 388 | + continue; |
|---|
| 438 | 389 | |
|---|
| 439 | | - case 88200: |
|---|
| 440 | | - table = tegra_hdmi_audio_88_2k; |
|---|
| 441 | | - break; |
|---|
| 390 | + /* Compute cts in 48.16 fixed point */ |
|---|
| 391 | + cts_f = ((int64_t)pix_clock << 16) * n; |
|---|
| 392 | + do_div(cts_f, afreq); |
|---|
| 393 | + /* Round it to the nearest integer */ |
|---|
| 394 | + cts = (cts_f & ~0xFFFF) + ((cts_f & BIT(15)) << 1); |
|---|
| 442 | 395 | |
|---|
| 443 | | - case 96000: |
|---|
| 444 | | - table = tegra_hdmi_audio_96k; |
|---|
| 445 | | - break; |
|---|
| 396 | + delta = abs(n - ideal_n); |
|---|
| 446 | 397 | |
|---|
| 447 | | - case 176400: |
|---|
| 448 | | - table = tegra_hdmi_audio_176_4k; |
|---|
| 449 | | - break; |
|---|
| 450 | | - |
|---|
| 451 | | - case 192000: |
|---|
| 452 | | - table = tegra_hdmi_audio_192k; |
|---|
| 453 | | - break; |
|---|
| 454 | | - |
|---|
| 455 | | - default: |
|---|
| 456 | | - return NULL; |
|---|
| 398 | + /* Compute the absolute error */ |
|---|
| 399 | + err = abs((int64_t)cts_f - cts); |
|---|
| 400 | + if (err < min_err || (err == min_err && delta < min_delta)) { |
|---|
| 401 | + config->n = n; |
|---|
| 402 | + config->cts = cts >> 16; |
|---|
| 403 | + config->aval = aval_f >> 16; |
|---|
| 404 | + min_delta = delta; |
|---|
| 405 | + min_err = err; |
|---|
| 406 | + } |
|---|
| 457 | 407 | } |
|---|
| 458 | 408 | |
|---|
| 459 | | - while (table->pclk) { |
|---|
| 460 | | - if (table->pclk == pclk) |
|---|
| 461 | | - return table; |
|---|
| 462 | | - |
|---|
| 463 | | - table++; |
|---|
| 464 | | - } |
|---|
| 465 | | - |
|---|
| 466 | | - return NULL; |
|---|
| 409 | + return config->n != -1 ? 0 : -EINVAL; |
|---|
| 467 | 410 | } |
|---|
| 468 | 411 | |
|---|
| 469 | 412 | static void tegra_hdmi_setup_audio_fs_tables(struct tegra_hdmi *hdmi) |
|---|
| .. | .. |
|---|
| 510 | 453 | unsigned int i; |
|---|
| 511 | 454 | |
|---|
| 512 | 455 | for (i = 0; i < ARRAY_SIZE(regs); i++) { |
|---|
| 513 | | - if (regs[i].sample_rate == hdmi->audio_sample_rate) { |
|---|
| 456 | + if (regs[i].sample_rate == hdmi->format.sample_rate) { |
|---|
| 514 | 457 | tegra_hdmi_writel(hdmi, value, regs[i].offset); |
|---|
| 515 | 458 | break; |
|---|
| 516 | 459 | } |
|---|
| .. | .. |
|---|
| 519 | 462 | |
|---|
| 520 | 463 | static int tegra_hdmi_setup_audio(struct tegra_hdmi *hdmi) |
|---|
| 521 | 464 | { |
|---|
| 522 | | - const struct tegra_hdmi_audio_config *config; |
|---|
| 465 | + struct tegra_hdmi_audio_config config; |
|---|
| 523 | 466 | u32 source, value; |
|---|
| 467 | + int err; |
|---|
| 524 | 468 | |
|---|
| 525 | 469 | switch (hdmi->audio_source) { |
|---|
| 526 | 470 | case HDA: |
|---|
| .. | .. |
|---|
| 564 | 508 | * play back system startup sounds early. It is possibly not |
|---|
| 565 | 509 | * needed on Linux at all. |
|---|
| 566 | 510 | */ |
|---|
| 567 | | - if (hdmi->audio_channels == 2) |
|---|
| 511 | + if (hdmi->format.channels == 2) |
|---|
| 568 | 512 | value = SOR_AUDIO_CNTRL0_INJECT_NULLSMPL; |
|---|
| 569 | 513 | else |
|---|
| 570 | 514 | value = 0; |
|---|
| .. | .. |
|---|
| 595 | 539 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_AUDIO_SPARE0); |
|---|
| 596 | 540 | } |
|---|
| 597 | 541 | |
|---|
| 598 | | - config = tegra_hdmi_get_audio_config(hdmi->audio_sample_rate, |
|---|
| 599 | | - hdmi->pixel_clock); |
|---|
| 600 | | - if (!config) { |
|---|
| 542 | + err = tegra_hdmi_get_audio_config(hdmi->format.sample_rate, |
|---|
| 543 | + hdmi->pixel_clock, &config); |
|---|
| 544 | + if (err < 0) { |
|---|
| 601 | 545 | dev_err(hdmi->dev, |
|---|
| 602 | 546 | "cannot set audio to %u Hz at %u Hz pixel clock\n", |
|---|
| 603 | | - hdmi->audio_sample_rate, hdmi->pixel_clock); |
|---|
| 604 | | - return -EINVAL; |
|---|
| 547 | + hdmi->format.sample_rate, hdmi->pixel_clock); |
|---|
| 548 | + return err; |
|---|
| 605 | 549 | } |
|---|
| 550 | + |
|---|
| 551 | + dev_dbg(hdmi->dev, "audio: pixclk=%u, n=%u, cts=%u, aval=%u\n", |
|---|
| 552 | + hdmi->pixel_clock, config.n, config.cts, config.aval); |
|---|
| 606 | 553 | |
|---|
| 607 | 554 | tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_HDMI_ACR_CTRL); |
|---|
| 608 | 555 | |
|---|
| 609 | 556 | value = AUDIO_N_RESETF | AUDIO_N_GENERATE_ALTERNATE | |
|---|
| 610 | | - AUDIO_N_VALUE(config->n - 1); |
|---|
| 557 | + AUDIO_N_VALUE(config.n - 1); |
|---|
| 611 | 558 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_AUDIO_N); |
|---|
| 612 | 559 | |
|---|
| 613 | | - tegra_hdmi_writel(hdmi, ACR_SUBPACK_N(config->n) | ACR_ENABLE, |
|---|
| 560 | + tegra_hdmi_writel(hdmi, ACR_SUBPACK_N(config.n) | ACR_ENABLE, |
|---|
| 614 | 561 | HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_HIGH); |
|---|
| 615 | 562 | |
|---|
| 616 | | - tegra_hdmi_writel(hdmi, ACR_SUBPACK_CTS(config->cts), |
|---|
| 563 | + tegra_hdmi_writel(hdmi, ACR_SUBPACK_CTS(config.cts), |
|---|
| 617 | 564 | HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_LOW); |
|---|
| 618 | 565 | |
|---|
| 619 | 566 | value = SPARE_HW_CTS | SPARE_FORCE_SW_CTS | SPARE_CTS_RESET_VAL(1); |
|---|
| .. | .. |
|---|
| 624 | 571 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_AUDIO_N); |
|---|
| 625 | 572 | |
|---|
| 626 | 573 | if (hdmi->config->has_hda) |
|---|
| 627 | | - tegra_hdmi_write_aval(hdmi, config->aval); |
|---|
| 574 | + tegra_hdmi_write_aval(hdmi, config.aval); |
|---|
| 628 | 575 | |
|---|
| 629 | 576 | tegra_hdmi_setup_audio_fs_tables(hdmi); |
|---|
| 630 | 577 | |
|---|
| .. | .. |
|---|
| 741 | 688 | u8 buffer[17]; |
|---|
| 742 | 689 | ssize_t err; |
|---|
| 743 | 690 | |
|---|
| 744 | | - err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false); |
|---|
| 691 | + err = drm_hdmi_avi_infoframe_from_display_mode(&frame, |
|---|
| 692 | + &hdmi->output.connector, mode); |
|---|
| 745 | 693 | if (err < 0) { |
|---|
| 746 | 694 | dev_err(hdmi->dev, "failed to setup AVI infoframe: %zd\n", err); |
|---|
| 747 | 695 | return; |
|---|
| .. | .. |
|---|
| 787 | 735 | return; |
|---|
| 788 | 736 | } |
|---|
| 789 | 737 | |
|---|
| 790 | | - frame.channels = hdmi->audio_channels; |
|---|
| 738 | + frame.channels = hdmi->format.channels; |
|---|
| 791 | 739 | |
|---|
| 792 | 740 | err = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); |
|---|
| 793 | 741 | if (err < 0) { |
|---|
| .. | .. |
|---|
| 1116 | 1064 | struct drm_minor *minor = connector->dev->primary; |
|---|
| 1117 | 1065 | struct dentry *root = connector->debugfs_entry; |
|---|
| 1118 | 1066 | struct tegra_hdmi *hdmi = to_hdmi(output); |
|---|
| 1119 | | - int err; |
|---|
| 1120 | 1067 | |
|---|
| 1121 | 1068 | hdmi->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files), |
|---|
| 1122 | 1069 | GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 1126 | 1073 | for (i = 0; i < count; i++) |
|---|
| 1127 | 1074 | hdmi->debugfs_files[i].data = hdmi; |
|---|
| 1128 | 1075 | |
|---|
| 1129 | | - err = drm_debugfs_create_files(hdmi->debugfs_files, count, root, minor); |
|---|
| 1130 | | - if (err < 0) |
|---|
| 1131 | | - goto free; |
|---|
| 1076 | + drm_debugfs_create_files(hdmi->debugfs_files, count, root, minor); |
|---|
| 1132 | 1077 | |
|---|
| 1133 | 1078 | return 0; |
|---|
| 1134 | | - |
|---|
| 1135 | | -free: |
|---|
| 1136 | | - kfree(hdmi->debugfs_files); |
|---|
| 1137 | | - hdmi->debugfs_files = NULL; |
|---|
| 1138 | | - |
|---|
| 1139 | | - return err; |
|---|
| 1140 | 1079 | } |
|---|
| 1141 | 1080 | |
|---|
| 1142 | 1081 | static void tegra_hdmi_early_unregister(struct drm_connector *connector) |
|---|
| .. | .. |
|---|
| 1188 | 1127 | .mode_valid = tegra_hdmi_connector_mode_valid, |
|---|
| 1189 | 1128 | }; |
|---|
| 1190 | 1129 | |
|---|
| 1191 | | -static const struct drm_encoder_funcs tegra_hdmi_encoder_funcs = { |
|---|
| 1192 | | - .destroy = tegra_output_encoder_destroy, |
|---|
| 1193 | | -}; |
|---|
| 1194 | | - |
|---|
| 1195 | 1130 | static void tegra_hdmi_encoder_disable(struct drm_encoder *encoder) |
|---|
| 1196 | 1131 | { |
|---|
| 1197 | 1132 | struct tegra_output *output = encoder_to_output(encoder); |
|---|
| 1198 | 1133 | struct tegra_dc *dc = to_tegra_dc(encoder->crtc); |
|---|
| 1199 | 1134 | struct tegra_hdmi *hdmi = to_hdmi(output); |
|---|
| 1200 | 1135 | u32 value; |
|---|
| 1136 | + int err; |
|---|
| 1201 | 1137 | |
|---|
| 1202 | 1138 | /* |
|---|
| 1203 | 1139 | * The following accesses registers of the display controller, so make |
|---|
| .. | .. |
|---|
| 1223 | 1159 | tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_INT_ENABLE); |
|---|
| 1224 | 1160 | tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_INT_MASK); |
|---|
| 1225 | 1161 | |
|---|
| 1226 | | - pm_runtime_put(hdmi->dev); |
|---|
| 1162 | + err = host1x_client_suspend(&hdmi->client); |
|---|
| 1163 | + if (err < 0) |
|---|
| 1164 | + dev_err(hdmi->dev, "failed to suspend: %d\n", err); |
|---|
| 1227 | 1165 | } |
|---|
| 1228 | 1166 | |
|---|
| 1229 | 1167 | static void tegra_hdmi_encoder_enable(struct drm_encoder *encoder) |
|---|
| .. | .. |
|---|
| 1238 | 1176 | u32 value; |
|---|
| 1239 | 1177 | int err; |
|---|
| 1240 | 1178 | |
|---|
| 1241 | | - pm_runtime_get_sync(hdmi->dev); |
|---|
| 1179 | + err = host1x_client_resume(&hdmi->client); |
|---|
| 1180 | + if (err < 0) { |
|---|
| 1181 | + dev_err(hdmi->dev, "failed to resume: %d\n", err); |
|---|
| 1182 | + return; |
|---|
| 1183 | + } |
|---|
| 1242 | 1184 | |
|---|
| 1243 | 1185 | /* |
|---|
| 1244 | 1186 | * Enable and unmask the HDA codec SCRATCH0 register interrupt. This |
|---|
| .. | .. |
|---|
| 1314 | 1256 | |
|---|
| 1315 | 1257 | hdmi->dvi = !tegra_output_is_hdmi(output); |
|---|
| 1316 | 1258 | if (!hdmi->dvi) { |
|---|
| 1317 | | - err = tegra_hdmi_setup_audio(hdmi); |
|---|
| 1318 | | - if (err < 0) |
|---|
| 1319 | | - hdmi->dvi = true; |
|---|
| 1259 | + /* |
|---|
| 1260 | + * Make sure that the audio format has been configured before |
|---|
| 1261 | + * enabling audio, otherwise we may try to divide by zero. |
|---|
| 1262 | + */ |
|---|
| 1263 | + if (hdmi->format.sample_rate > 0) { |
|---|
| 1264 | + err = tegra_hdmi_setup_audio(hdmi); |
|---|
| 1265 | + if (err < 0) |
|---|
| 1266 | + hdmi->dvi = true; |
|---|
| 1267 | + } |
|---|
| 1320 | 1268 | } |
|---|
| 1321 | 1269 | |
|---|
| 1322 | 1270 | if (hdmi->config->has_hda) |
|---|
| .. | .. |
|---|
| 1470 | 1418 | |
|---|
| 1471 | 1419 | static int tegra_hdmi_init(struct host1x_client *client) |
|---|
| 1472 | 1420 | { |
|---|
| 1473 | | - struct drm_device *drm = dev_get_drvdata(client->parent); |
|---|
| 1474 | 1421 | struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client); |
|---|
| 1422 | + struct drm_device *drm = dev_get_drvdata(client->host); |
|---|
| 1475 | 1423 | int err; |
|---|
| 1476 | 1424 | |
|---|
| 1477 | 1425 | hdmi->output.dev = client->dev; |
|---|
| 1478 | 1426 | |
|---|
| 1479 | | - drm_connector_init(drm, &hdmi->output.connector, |
|---|
| 1480 | | - &tegra_hdmi_connector_funcs, |
|---|
| 1481 | | - DRM_MODE_CONNECTOR_HDMIA); |
|---|
| 1427 | + drm_connector_init_with_ddc(drm, &hdmi->output.connector, |
|---|
| 1428 | + &tegra_hdmi_connector_funcs, |
|---|
| 1429 | + DRM_MODE_CONNECTOR_HDMIA, |
|---|
| 1430 | + hdmi->output.ddc); |
|---|
| 1482 | 1431 | drm_connector_helper_add(&hdmi->output.connector, |
|---|
| 1483 | 1432 | &tegra_hdmi_connector_helper_funcs); |
|---|
| 1484 | 1433 | hdmi->output.connector.dpms = DRM_MODE_DPMS_OFF; |
|---|
| 1485 | 1434 | |
|---|
| 1486 | | - drm_encoder_init(drm, &hdmi->output.encoder, &tegra_hdmi_encoder_funcs, |
|---|
| 1487 | | - DRM_MODE_ENCODER_TMDS, NULL); |
|---|
| 1435 | + drm_simple_encoder_init(drm, &hdmi->output.encoder, |
|---|
| 1436 | + DRM_MODE_ENCODER_TMDS); |
|---|
| 1488 | 1437 | drm_encoder_helper_add(&hdmi->output.encoder, |
|---|
| 1489 | 1438 | &tegra_hdmi_encoder_helper_funcs); |
|---|
| 1490 | 1439 | |
|---|
| .. | .. |
|---|
| 1535 | 1484 | return 0; |
|---|
| 1536 | 1485 | } |
|---|
| 1537 | 1486 | |
|---|
| 1487 | +static int tegra_hdmi_runtime_suspend(struct host1x_client *client) |
|---|
| 1488 | +{ |
|---|
| 1489 | + struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client); |
|---|
| 1490 | + struct device *dev = client->dev; |
|---|
| 1491 | + int err; |
|---|
| 1492 | + |
|---|
| 1493 | + err = reset_control_assert(hdmi->rst); |
|---|
| 1494 | + if (err < 0) { |
|---|
| 1495 | + dev_err(dev, "failed to assert reset: %d\n", err); |
|---|
| 1496 | + return err; |
|---|
| 1497 | + } |
|---|
| 1498 | + |
|---|
| 1499 | + usleep_range(1000, 2000); |
|---|
| 1500 | + |
|---|
| 1501 | + clk_disable_unprepare(hdmi->clk); |
|---|
| 1502 | + pm_runtime_put_sync(dev); |
|---|
| 1503 | + |
|---|
| 1504 | + return 0; |
|---|
| 1505 | +} |
|---|
| 1506 | + |
|---|
| 1507 | +static int tegra_hdmi_runtime_resume(struct host1x_client *client) |
|---|
| 1508 | +{ |
|---|
| 1509 | + struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client); |
|---|
| 1510 | + struct device *dev = client->dev; |
|---|
| 1511 | + int err; |
|---|
| 1512 | + |
|---|
| 1513 | + err = pm_runtime_resume_and_get(dev); |
|---|
| 1514 | + if (err < 0) { |
|---|
| 1515 | + dev_err(dev, "failed to get runtime PM: %d\n", err); |
|---|
| 1516 | + return err; |
|---|
| 1517 | + } |
|---|
| 1518 | + |
|---|
| 1519 | + err = clk_prepare_enable(hdmi->clk); |
|---|
| 1520 | + if (err < 0) { |
|---|
| 1521 | + dev_err(dev, "failed to enable clock: %d\n", err); |
|---|
| 1522 | + goto put_rpm; |
|---|
| 1523 | + } |
|---|
| 1524 | + |
|---|
| 1525 | + usleep_range(1000, 2000); |
|---|
| 1526 | + |
|---|
| 1527 | + err = reset_control_deassert(hdmi->rst); |
|---|
| 1528 | + if (err < 0) { |
|---|
| 1529 | + dev_err(dev, "failed to deassert reset: %d\n", err); |
|---|
| 1530 | + goto disable_clk; |
|---|
| 1531 | + } |
|---|
| 1532 | + |
|---|
| 1533 | + return 0; |
|---|
| 1534 | + |
|---|
| 1535 | +disable_clk: |
|---|
| 1536 | + clk_disable_unprepare(hdmi->clk); |
|---|
| 1537 | +put_rpm: |
|---|
| 1538 | + pm_runtime_put_sync(dev); |
|---|
| 1539 | + return err; |
|---|
| 1540 | +} |
|---|
| 1541 | + |
|---|
| 1538 | 1542 | static const struct host1x_client_ops hdmi_client_ops = { |
|---|
| 1539 | 1543 | .init = tegra_hdmi_init, |
|---|
| 1540 | 1544 | .exit = tegra_hdmi_exit, |
|---|
| 1545 | + .suspend = tegra_hdmi_runtime_suspend, |
|---|
| 1546 | + .resume = tegra_hdmi_runtime_resume, |
|---|
| 1541 | 1547 | }; |
|---|
| 1542 | 1548 | |
|---|
| 1543 | 1549 | static const struct tegra_hdmi_config tegra20_hdmi_config = { |
|---|
| .. | .. |
|---|
| 1589 | 1595 | }; |
|---|
| 1590 | 1596 | MODULE_DEVICE_TABLE(of, tegra_hdmi_of_match); |
|---|
| 1591 | 1597 | |
|---|
| 1592 | | -static void hda_format_parse(unsigned int format, unsigned int *rate, |
|---|
| 1593 | | - unsigned int *channels) |
|---|
| 1594 | | -{ |
|---|
| 1595 | | - unsigned int mul, div; |
|---|
| 1596 | | - |
|---|
| 1597 | | - if (format & AC_FMT_BASE_44K) |
|---|
| 1598 | | - *rate = 44100; |
|---|
| 1599 | | - else |
|---|
| 1600 | | - *rate = 48000; |
|---|
| 1601 | | - |
|---|
| 1602 | | - mul = (format & AC_FMT_MULT_MASK) >> AC_FMT_MULT_SHIFT; |
|---|
| 1603 | | - div = (format & AC_FMT_DIV_MASK) >> AC_FMT_DIV_SHIFT; |
|---|
| 1604 | | - |
|---|
| 1605 | | - *rate = *rate * (mul + 1) / (div + 1); |
|---|
| 1606 | | - |
|---|
| 1607 | | - *channels = (format & AC_FMT_CHAN_MASK) >> AC_FMT_CHAN_SHIFT; |
|---|
| 1608 | | -} |
|---|
| 1609 | | - |
|---|
| 1610 | 1598 | static irqreturn_t tegra_hdmi_irq(int irq, void *data) |
|---|
| 1611 | 1599 | { |
|---|
| 1612 | 1600 | struct tegra_hdmi *hdmi = data; |
|---|
| .. | .. |
|---|
| 1623 | 1611 | value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_SOR_AUDIO_HDA_CODEC_SCRATCH0); |
|---|
| 1624 | 1612 | |
|---|
| 1625 | 1613 | if (value & SOR_AUDIO_HDA_CODEC_SCRATCH0_VALID) { |
|---|
| 1626 | | - unsigned int sample_rate, channels; |
|---|
| 1627 | | - |
|---|
| 1628 | 1614 | format = value & SOR_AUDIO_HDA_CODEC_SCRATCH0_FMT_MASK; |
|---|
| 1629 | 1615 | |
|---|
| 1630 | | - hda_format_parse(format, &sample_rate, &channels); |
|---|
| 1631 | | - |
|---|
| 1632 | | - hdmi->audio_sample_rate = sample_rate; |
|---|
| 1633 | | - hdmi->audio_channels = channels; |
|---|
| 1616 | + tegra_hda_parse_format(format, &hdmi->format); |
|---|
| 1634 | 1617 | |
|---|
| 1635 | 1618 | err = tegra_hdmi_setup_audio(hdmi); |
|---|
| 1636 | 1619 | if (err < 0) { |
|---|
| .. | .. |
|---|
| 1652 | 1635 | |
|---|
| 1653 | 1636 | static int tegra_hdmi_probe(struct platform_device *pdev) |
|---|
| 1654 | 1637 | { |
|---|
| 1638 | + const char *level = KERN_ERR; |
|---|
| 1655 | 1639 | struct tegra_hdmi *hdmi; |
|---|
| 1656 | 1640 | struct resource *regs; |
|---|
| 1657 | 1641 | int err; |
|---|
| .. | .. |
|---|
| 1664 | 1648 | hdmi->dev = &pdev->dev; |
|---|
| 1665 | 1649 | |
|---|
| 1666 | 1650 | hdmi->audio_source = AUTO; |
|---|
| 1667 | | - hdmi->audio_sample_rate = 48000; |
|---|
| 1668 | | - hdmi->audio_channels = 2; |
|---|
| 1669 | 1651 | hdmi->stereo = false; |
|---|
| 1670 | 1652 | hdmi->dvi = false; |
|---|
| 1671 | 1653 | |
|---|
| .. | .. |
|---|
| 1692 | 1674 | } |
|---|
| 1693 | 1675 | |
|---|
| 1694 | 1676 | hdmi->hdmi = devm_regulator_get(&pdev->dev, "hdmi"); |
|---|
| 1695 | | - if (IS_ERR(hdmi->hdmi)) { |
|---|
| 1696 | | - dev_err(&pdev->dev, "failed to get HDMI regulator\n"); |
|---|
| 1697 | | - return PTR_ERR(hdmi->hdmi); |
|---|
| 1677 | + err = PTR_ERR_OR_ZERO(hdmi->hdmi); |
|---|
| 1678 | + if (err) { |
|---|
| 1679 | + if (err == -EPROBE_DEFER) |
|---|
| 1680 | + level = KERN_DEBUG; |
|---|
| 1681 | + |
|---|
| 1682 | + dev_printk(level, &pdev->dev, |
|---|
| 1683 | + "failed to get HDMI regulator: %d\n", err); |
|---|
| 1684 | + return err; |
|---|
| 1698 | 1685 | } |
|---|
| 1699 | 1686 | |
|---|
| 1700 | 1687 | hdmi->pll = devm_regulator_get(&pdev->dev, "pll"); |
|---|
| 1701 | | - if (IS_ERR(hdmi->pll)) { |
|---|
| 1702 | | - dev_err(&pdev->dev, "failed to get PLL regulator\n"); |
|---|
| 1703 | | - return PTR_ERR(hdmi->pll); |
|---|
| 1688 | + err = PTR_ERR_OR_ZERO(hdmi->pll); |
|---|
| 1689 | + if (err) { |
|---|
| 1690 | + if (err == -EPROBE_DEFER) |
|---|
| 1691 | + level = KERN_DEBUG; |
|---|
| 1692 | + |
|---|
| 1693 | + dev_printk(level, &pdev->dev, |
|---|
| 1694 | + "failed to get PLL regulator: %d\n", err); |
|---|
| 1695 | + return err; |
|---|
| 1704 | 1696 | } |
|---|
| 1705 | 1697 | |
|---|
| 1706 | 1698 | hdmi->vdd = devm_regulator_get(&pdev->dev, "vdd"); |
|---|
| 1707 | | - if (IS_ERR(hdmi->vdd)) { |
|---|
| 1708 | | - dev_err(&pdev->dev, "failed to get VDD regulator\n"); |
|---|
| 1709 | | - return PTR_ERR(hdmi->vdd); |
|---|
| 1710 | | - } |
|---|
| 1699 | + err = PTR_ERR_OR_ZERO(hdmi->vdd); |
|---|
| 1700 | + if (err) { |
|---|
| 1701 | + if (err == -EPROBE_DEFER) |
|---|
| 1702 | + level = KERN_DEBUG; |
|---|
| 1711 | 1703 | |
|---|
| 1712 | | - hdmi->output.notifier = cec_notifier_get(&pdev->dev); |
|---|
| 1713 | | - if (hdmi->output.notifier == NULL) |
|---|
| 1714 | | - return -ENOMEM; |
|---|
| 1704 | + dev_printk(level, &pdev->dev, |
|---|
| 1705 | + "failed to get VDD regulator: %d\n", err); |
|---|
| 1706 | + return err; |
|---|
| 1707 | + } |
|---|
| 1715 | 1708 | |
|---|
| 1716 | 1709 | hdmi->output.dev = &pdev->dev; |
|---|
| 1717 | 1710 | |
|---|
| .. | .. |
|---|
| 1771 | 1764 | |
|---|
| 1772 | 1765 | tegra_output_remove(&hdmi->output); |
|---|
| 1773 | 1766 | |
|---|
| 1774 | | - if (hdmi->output.notifier) |
|---|
| 1775 | | - cec_notifier_put(hdmi->output.notifier); |
|---|
| 1776 | | - |
|---|
| 1777 | 1767 | return 0; |
|---|
| 1778 | 1768 | } |
|---|
| 1779 | | - |
|---|
| 1780 | | -#ifdef CONFIG_PM |
|---|
| 1781 | | -static int tegra_hdmi_suspend(struct device *dev) |
|---|
| 1782 | | -{ |
|---|
| 1783 | | - struct tegra_hdmi *hdmi = dev_get_drvdata(dev); |
|---|
| 1784 | | - int err; |
|---|
| 1785 | | - |
|---|
| 1786 | | - err = reset_control_assert(hdmi->rst); |
|---|
| 1787 | | - if (err < 0) { |
|---|
| 1788 | | - dev_err(dev, "failed to assert reset: %d\n", err); |
|---|
| 1789 | | - return err; |
|---|
| 1790 | | - } |
|---|
| 1791 | | - |
|---|
| 1792 | | - usleep_range(1000, 2000); |
|---|
| 1793 | | - |
|---|
| 1794 | | - clk_disable_unprepare(hdmi->clk); |
|---|
| 1795 | | - |
|---|
| 1796 | | - return 0; |
|---|
| 1797 | | -} |
|---|
| 1798 | | - |
|---|
| 1799 | | -static int tegra_hdmi_resume(struct device *dev) |
|---|
| 1800 | | -{ |
|---|
| 1801 | | - struct tegra_hdmi *hdmi = dev_get_drvdata(dev); |
|---|
| 1802 | | - int err; |
|---|
| 1803 | | - |
|---|
| 1804 | | - err = clk_prepare_enable(hdmi->clk); |
|---|
| 1805 | | - if (err < 0) { |
|---|
| 1806 | | - dev_err(dev, "failed to enable clock: %d\n", err); |
|---|
| 1807 | | - return err; |
|---|
| 1808 | | - } |
|---|
| 1809 | | - |
|---|
| 1810 | | - usleep_range(1000, 2000); |
|---|
| 1811 | | - |
|---|
| 1812 | | - err = reset_control_deassert(hdmi->rst); |
|---|
| 1813 | | - if (err < 0) { |
|---|
| 1814 | | - dev_err(dev, "failed to deassert reset: %d\n", err); |
|---|
| 1815 | | - clk_disable_unprepare(hdmi->clk); |
|---|
| 1816 | | - return err; |
|---|
| 1817 | | - } |
|---|
| 1818 | | - |
|---|
| 1819 | | - return 0; |
|---|
| 1820 | | -} |
|---|
| 1821 | | -#endif |
|---|
| 1822 | | - |
|---|
| 1823 | | -static const struct dev_pm_ops tegra_hdmi_pm_ops = { |
|---|
| 1824 | | - SET_RUNTIME_PM_OPS(tegra_hdmi_suspend, tegra_hdmi_resume, NULL) |
|---|
| 1825 | | -}; |
|---|
| 1826 | 1769 | |
|---|
| 1827 | 1770 | struct platform_driver tegra_hdmi_driver = { |
|---|
| 1828 | 1771 | .driver = { |
|---|
| 1829 | 1772 | .name = "tegra-hdmi", |
|---|
| 1830 | 1773 | .of_match_table = tegra_hdmi_of_match, |
|---|
| 1831 | | - .pm = &tegra_hdmi_pm_ops, |
|---|
| 1832 | 1774 | }, |
|---|
| 1833 | 1775 | .probe = tegra_hdmi_probe, |
|---|
| 1834 | 1776 | .remove = tegra_hdmi_remove, |
|---|