/*
* dc.c: dc driver.
*
* Copyright (C) 2010 Google, Inc.
* Author: Erik Gilling <konkers@android.com>
*
* Copyright (c) 2010-2020, NVIDIA CORPORATION, All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/pm.h>
#include <linux/tegra-pm.h>
#include <linux/pm_runtime.h>
#include <linux/of_device.h>
#include <linux/clk.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/workqueue.h>
#include <linux/ktime.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/backlight.h>
#include <linux/gpio.h>
#include <linux/nvhost.h>
#include <linux/clk/tegra.h>
#include <linux/platform/tegra/emc_bwmgr.h>
#include <uapi/video/tegrafb.h>
#include <drm/drm_fixed.h>
#include <linux/dma-buf.h>
#include <linux/extcon/extcon-disp.h>
#include <linux/extcon.h>
#ifdef CONFIG_SWITCH
#include <linux/switch.h>
#endif
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/tegra_pm_domains.h>
#include <linux/uaccess.h>
#if defined(CONFIG_TRUSTED_LITTLE_KERNEL) || defined(CONFIG_TRUSTY)
#include <linux/ote_protocol.h>
#endif
#include <linux/version.h>
#include <clocksource/arm_arch_timer.h>
#define CREATE_TRACE_POINTS
#include <trace/events/display.h>
EXPORT_TRACEPOINT_SYMBOL(display_writel);
EXPORT_TRACEPOINT_SYMBOL(display_readl);
#include <linux/nvhost.h>
#include <uapi/linux/nvhost_ioctl.h>
#include <linux/platform/tegra/latency_allowance.h>
#include <linux/platform/tegra/mc.h>
#include <soc/tegra/tegra_bpmp.h>
#include <uapi/video/tegra_dc_ext.h>
#include "dc.h"
#include "dc_reg.h"
#include "dc_config.h"
#include "dc_priv.h"
#include "dc_shared_isr.h"
#include "nvhost_sync.h"
#include "nvhost_syncpt.h" /* Preset and flush vblank_syncpt*/
#include "dpaux.h"
#include "lvds.h"
#include "dc_common.h"
#include "edid.h"
#ifdef CONFIG_TEGRA_DC_FAKE_PANEL_SUPPORT
#include "fake_panel.h"
#endif /*CONFIG_TEGRA_DC_FAKE_PANEL_SUPPORT*/
/* HACK! This needs to come from DT */
#include "../../../../arch/arm/mach-tegra/iomap.h"
#define TEGRA_CRC_LATCHED_DELAY 34
#define DC_COM_PIN_OUTPUT_POLARITY1_INIT_VAL 0x01000000
#define DC_COM_PIN_OUTPUT_POLARITY3_INIT_VAL 0x0
#define MAX_VRR_V_FRONT_PORCH 0x1000
static struct tegra_dc_hw_data *hw_data;
static struct tegra_dc_hw_data t21x_hw_data;
static struct tegra_dc_hw_data t18x_hw_data;
static struct tegra_dc_hw_data t19x_hw_data;
static const struct of_device_id tegra_display_of_match[] = {
{.compatible = "nvidia,tegra210-dc", .data = &t21x_hw_data },
{.compatible = "nvidia,tegra186-dc", .data = &t18x_hw_data },
{.compatible = "nvidia,tegra194-dc", .data = &t19x_hw_data },
{ },
};
MODULE_DEVICE_TABLE(of, tegra_display_of_match);
/* Used only on T21x*/
static struct of_device_id tegra_disa_pd[] = {
{ .compatible = "nvidia,tegra210-disa-pd", },
{},
};
/* Used only on T21x */
static struct of_device_id tegra_disb_pd[] = {
{ .compatible = "nvidia,tegra210-disb-pd", },
{},
};
static unsigned int display_la_emc_client_id[] = {
TEGRA_BWMGR_CLIENT_DISP1_LA_EMC,
TEGRA_BWMGR_CLIENT_DISP2_LA_EMC
};
struct fb_videomode tegra_dc_vga_mode = {
.refresh = 60,
.xres = 640,
.yres = 480,
.pixclock = KHZ2PICOS(25200),
.hsync_len = 96, /* h_sync_width */
.vsync_len = 2, /* v_sync_width */
.left_margin = 48, /* h_back_porch */
.upper_margin = 33, /* v_back_porch */
.right_margin = 16, /* h_front_porch */
.lower_margin = 10, /* v_front_porch */
.vmode = 0,
.sync = 0,
};
/* needs to be big enough to be index by largest supported out->type */
static struct tegra_dc_mode override_disp_mode[TEGRA_DC_OUT_NULL + 1];
static void _tegra_dc_controller_disable(struct tegra_dc *dc);
static void tegra_dc_disable_irq_ops(struct tegra_dc *dc, bool from_irq);
static int _tegra_dc_config_frame_end_intr(struct tegra_dc *dc, bool enable);
static int tegra_dc_set_out(struct tegra_dc *dc, struct tegra_dc_out *out,
bool initialized);
#ifdef PM
static int tegra_dc_suspend(struct platform_device *ndev, pm_message_t state);
static int tegra_dc_resume(struct platform_device *ndev);
#endif
static struct tegra_dc **tegra_dcs;
/* Used only on Nvdisplay */
static struct tegra_dc_win tegra_dc_windows[DC_N_WINDOWS];
static u64 tegra_dc_get_scanline_timestamp(struct tegra_dc *dc,
const u32 scanline);
static void tegra_dc_collect_latency_data(struct tegra_dc *dc);
static DEFINE_MUTEX(tegra_dc_lock);
/* Lock to serialize extcon switch reporting across heads*/
static DEFINE_MUTEX(tegra_dc_extcon_lock);
/* Lock to serialize dc registration during probe */
static DEFINE_MUTEX(tegra_dc_registration_lock);
static struct device_dma_parameters tegra_dc_dma_parameters = {
.max_segment_size = UINT_MAX,
};
static const struct {
bool h;
bool v;
} can_filter[] = {
/* Window A has no filtering */
{ false, false },
/* Window B has both H and V filtering */
{ true, true },
/* Window C has only H filtering */
{ false, true },
};
static struct tegra_dc_cmu default_cmu = {
/* lut1 maps sRGB to linear space. */
{
0, 1, 2, 4, 5, 6, 7, 9,
10, 11, 12, 14, 15, 16, 18, 20,
21, 23, 25, 27, 29, 31, 33, 35,
37, 40, 42, 45, 48, 50, 53, 56,
59, 62, 66, 69, 72, 76, 79, 83,
87, 91, 95, 99, 103, 107, 112, 116,
121, 126, 131, 136, 141, 146, 151, 156,
162, 168, 173, 179, 185, 191, 197, 204,
210, 216, 223, 230, 237, 244, 251, 258,
265, 273, 280, 288, 296, 304, 312, 320,
329, 337, 346, 354, 363, 372, 381, 390,
400, 409, 419, 428, 438, 448, 458, 469,
479, 490, 500, 511, 522, 533, 544, 555,
567, 578, 590, 602, 614, 626, 639, 651,
664, 676, 689, 702, 715, 728, 742, 755,
769, 783, 797, 811, 825, 840, 854, 869,
884, 899, 914, 929, 945, 960, 976, 992,
1008, 1024, 1041, 1057, 1074, 1091, 1108, 1125,
1142, 1159, 1177, 1195, 1213, 1231, 1249, 1267,
1286, 1304, 1323, 1342, 1361, 1381, 1400, 1420,
1440, 1459, 1480, 1500, 1520, 1541, 1562, 1582,
1603, 1625, 1646, 1668, 1689, 1711, 1733, 1755,
1778, 1800, 1823, 1846, 1869, 1892, 1916, 1939,
1963, 1987, 2011, 2035, 2059, 2084, 2109, 2133,
2159, 2184, 2209, 2235, 2260, 2286, 2312, 2339,
2365, 2392, 2419, 2446, 2473, 2500, 2527, 2555,
2583, 2611, 2639, 2668, 2696, 2725, 2754, 2783,
2812, 2841, 2871, 2901, 2931, 2961, 2991, 3022,
3052, 3083, 3114, 3146, 3177, 3209, 3240, 3272,
3304, 3337, 3369, 3402, 3435, 3468, 3501, 3535,
3568, 3602, 3636, 3670, 3705, 3739, 3774, 3809,
3844, 3879, 3915, 3950, 3986, 4022, 4059, 4095,
},
/* csc */
{
0x100, 0x0, 0x0,
0x0, 0x100, 0x0,
0x0, 0x0, 0x100,
},
/* lut2 maps linear space to sRGB*/
{
0, 1, 2, 2, 3, 4, 5, 6,
6, 7, 8, 9, 10, 10, 11, 12,
13, 13, 14, 15, 15, 16, 16, 17,
18, 18, 19, 19, 20, 20, 21, 21,
22, 22, 23, 23, 23, 24, 24, 25,
25, 25, 26, 26, 27, 27, 27, 28,
28, 29, 29, 29, 30, 30, 30, 31,
31, 31, 32, 32, 32, 33, 33, 33,
34, 34, 34, 34, 35, 35, 35, 36,
36, 36, 37, 37, 37, 37, 38, 38,
38, 38, 39, 39, 39, 40, 40, 40,
40, 41, 41, 41, 41, 42, 42, 42,
42, 43, 43, 43, 43, 43, 44, 44,
44, 44, 45, 45, 45, 45, 46, 46,
46, 46, 46, 47, 47, 47, 47, 48,
48, 48, 48, 48, 49, 49, 49, 49,
49, 50, 50, 50, 50, 50, 51, 51,
51, 51, 51, 52, 52, 52, 52, 52,
53, 53, 53, 53, 53, 54, 54, 54,
54, 54, 55, 55, 55, 55, 55, 55,
56, 56, 56, 56, 56, 57, 57, 57,
57, 57, 57, 58, 58, 58, 58, 58,
58, 59, 59, 59, 59, 59, 59, 60,
60, 60, 60, 60, 60, 61, 61, 61,
61, 61, 61, 62, 62, 62, 62, 62,
62, 63, 63, 63, 63, 63, 63, 64,
64, 64, 64, 64, 64, 64, 65, 65,
65, 65, 65, 65, 66, 66, 66, 66,
66, 66, 66, 67, 67, 67, 67, 67,
67, 67, 68, 68, 68, 68, 68, 68,
68, 69, 69, 69, 69, 69, 69, 69,
70, 70, 70, 70, 70, 70, 70, 71,
71, 71, 71, 71, 71, 71, 72, 72,
72, 72, 72, 72, 72, 72, 73, 73,
73, 73, 73, 73, 73, 74, 74, 74,
74, 74, 74, 74, 74, 75, 75, 75,
75, 75, 75, 75, 75, 76, 76, 76,
76, 76, 76, 76, 77, 77, 77, 77,
77, 77, 77, 77, 78, 78, 78, 78,
78, 78, 78, 78, 78, 79, 79, 79,
79, 79, 79, 79, 79, 80, 80, 80,
80, 80, 80, 80, 80, 81, 81, 81,
81, 81, 81, 81, 81, 81, 82, 82,
82, 82, 82, 82, 82, 82, 83, 83,
83, 83, 83, 83, 83, 83, 83, 84,
84, 84, 84, 84, 84, 84, 84, 84,
85, 85, 85, 85, 85, 85, 85, 85,
85, 86, 86, 86, 86, 86, 86, 86,
86, 86, 87, 87, 87, 87, 87, 87,
87, 87, 87, 88, 88, 88, 88, 88,
88, 88, 88, 88, 88, 89, 89, 89,
89, 89, 89, 89, 89, 89, 90, 90,
90, 90, 90, 90, 90, 90, 90, 90,
91, 91, 91, 91, 91, 91, 91, 91,
91, 91, 92, 92, 92, 92, 92, 92,
92, 92, 92, 92, 93, 93, 93, 93,
93, 93, 93, 93, 93, 93, 94, 94,
94, 94, 94, 94, 94, 94, 94, 94,
95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 96, 96, 96, 96, 96, 96,
96, 96, 96, 96, 96, 97, 97, 97,
97, 97, 97, 97, 97, 97, 97, 98,
98, 98, 98, 98, 98, 98, 98, 98,
98, 98, 99, 99, 99, 99, 99, 99,
99, 100, 101, 101, 102, 103, 103, 104,
105, 105, 106, 107, 107, 108, 109, 109,
110, 111, 111, 112, 113, 113, 114, 115,
115, 116, 116, 117, 118, 118, 119, 119,
120, 120, 121, 122, 122, 123, 123, 124,
124, 125, 126, 126, 127, 127, 128, 128,
129, 129, 130, 130, 131, 131, 132, 132,
133, 133, 134, 134, 135, 135, 136, 136,
137, 137, 138, 138, 139, 139, 140, 140,
141, 141, 142, 142, 143, 143, 144, 144,
145, 145, 145, 146, 146, 147, 147, 148,
148, 149, 149, 150, 150, 150, 151, 151,
152, 152, 153, 153, 153, 154, 154, 155,
155, 156, 156, 156, 157, 157, 158, 158,
158, 159, 159, 160, 160, 160, 161, 161,
162, 162, 162, 163, 163, 164, 164, 164,
165, 165, 166, 166, 166, 167, 167, 167,
168, 168, 169, 169, 169, 170, 170, 170,
171, 171, 172, 172, 172, 173, 173, 173,
174, 174, 174, 175, 175, 176, 176, 176,
177, 177, 177, 178, 178, 178, 179, 179,
179, 180, 180, 180, 181, 181, 182, 182,
182, 183, 183, 183, 184, 184, 184, 185,
185, 185, 186, 186, 186, 187, 187, 187,
188, 188, 188, 189, 189, 189, 189, 190,
190, 190, 191, 191, 191, 192, 192, 192,
193, 193, 193, 194, 194, 194, 195, 195,
195, 196, 196, 196, 196, 197, 197, 197,
198, 198, 198, 199, 199, 199, 200, 200,
200, 200, 201, 201, 201, 202, 202, 202,
202, 203, 203, 203, 204, 204, 204, 205,
205, 205, 205, 206, 206, 206, 207, 207,
207, 207, 208, 208, 208, 209, 209, 209,
209, 210, 210, 210, 211, 211, 211, 211,
212, 212, 212, 213, 213, 213, 213, 214,
214, 214, 214, 215, 215, 215, 216, 216,
216, 216, 217, 217, 217, 217, 218, 218,
218, 219, 219, 219, 219, 220, 220, 220,
220, 221, 221, 221, 221, 222, 222, 222,
223, 223, 223, 223, 224, 224, 224, 224,
225, 225, 225, 225, 226, 226, 226, 226,
227, 227, 227, 227, 228, 228, 228, 228,
229, 229, 229, 229, 230, 230, 230, 230,
231, 231, 231, 231, 232, 232, 232, 232,
233, 233, 233, 233, 234, 234, 234, 234,
235, 235, 235, 235, 236, 236, 236, 236,
237, 237, 237, 237, 238, 238, 238, 238,
239, 239, 239, 239, 240, 240, 240, 240,
240, 241, 241, 241, 241, 242, 242, 242,
242, 243, 243, 243, 243, 244, 244, 244,
244, 244, 245, 245, 245, 245, 246, 246,
246, 246, 247, 247, 247, 247, 247, 248,
248, 248, 248, 249, 249, 249, 249, 249,
250, 250, 250, 250, 251, 251, 251, 251,
251, 252, 252, 252, 252, 253, 253, 253,
253, 253, 254, 254, 254, 254, 255, 255,
},
};
static struct tegra_dc_cmu default_limited_cmu = {
/* lut1 maps sRGB to linear space. */
{
0, 1, 2, 4, 5, 6, 7, 9,
10, 11, 12, 14, 15, 16, 18, 20,
21, 23, 25, 27, 29, 31, 33, 35,
37, 40, 42, 45, 48, 50, 53, 56,
59, 62, 66, 69, 72, 76, 79, 83,
87, 91, 95, 99, 103, 107, 112, 116,
121, 126, 131, 136, 141, 146, 151, 156,
162, 168, 173, 179, 185, 191, 197, 204,
210, 216, 223, 230, 237, 244, 251, 258,
265, 273, 280, 288, 296, 304, 312, 320,
329, 337, 346, 354, 363, 372, 381, 390,
400, 409, 419, 428, 438, 448, 458, 469,
479, 490, 500, 511, 522, 533, 544, 555,
567, 578, 590, 602, 614, 626, 639, 651,
664, 676, 689, 702, 715, 728, 742, 755,
769, 783, 797, 811, 825, 840, 854, 869,
884, 899, 914, 929, 945, 960, 976, 992,
1008, 1024, 1041, 1057, 1074, 1091, 1108, 1125,
1142, 1159, 1177, 1195, 1213, 1231, 1249, 1267,
1286, 1304, 1323, 1342, 1361, 1381, 1400, 1420,
1440, 1459, 1480, 1500, 1520, 1541, 1562, 1582,
1603, 1625, 1646, 1668, 1689, 1711, 1733, 1755,
1778, 1800, 1823, 1846, 1869, 1892, 1916, 1939,
1963, 1987, 2011, 2035, 2059, 2084, 2109, 2133,
2159, 2184, 2209, 2235, 2260, 2286, 2312, 2339,
2365, 2392, 2419, 2446, 2473, 2500, 2527, 2555,
2583, 2611, 2639, 2668, 2696, 2725, 2754, 2783,
2812, 2841, 2871, 2901, 2931, 2961, 2991, 3022,
3052, 3083, 3114, 3146, 3177, 3209, 3240, 3272,
3304, 3337, 3369, 3402, 3435, 3468, 3501, 3535,
3568, 3602, 3636, 3670, 3705, 3739, 3774, 3809,
3844, 3879, 3915, 3950, 3986, 4022, 4059, 4095,
},
/* csc */
{
0x100, 0x000, 0x000,
0x000, 0x100, 0x000,
0x000, 0x000, 0x100,
},
/*
* lut2 maps linear space back to sRGB, where
* the output range is [16...235] (limited).
*/
{
16, 17, 18, 18, 19, 19, 20, 21,
21, 22, 23, 24, 25, 25, 25, 26,
27, 27, 28, 28, 29, 30, 30, 31,
31, 31, 31, 32, 32, 33, 33, 34,
34, 35, 35, 36, 36, 37, 37, 37,
37, 37, 38, 38, 38, 39, 39, 39,
40, 40, 41, 41, 41, 42, 42, 42,
43, 43, 43, 43, 43, 43, 44, 44,
44, 44, 45, 45, 45, 46, 46, 46,
47, 47, 47, 47, 48, 48, 48, 49,
49, 49, 49, 49, 49, 49, 49, 50,
50, 50, 50, 51, 51, 51, 51, 52,
52, 52, 52, 53, 53, 53, 53, 54,
54, 54, 54, 55, 55, 55, 55, 55,
56, 56, 56, 56, 56, 56, 56, 56,
56, 57, 57, 57, 57, 57, 58, 58,
58, 58, 58, 59, 59, 59, 59, 59,
60, 60, 60, 60, 60, 61, 61, 61,
61, 61, 62, 62, 62, 62, 62, 62,
62, 62, 62, 62, 63, 63, 63, 63,
63, 63, 64, 64, 64, 64, 64, 64,
65, 65, 65, 65, 65, 66, 66, 66,
66, 66, 66, 67, 67, 67, 67, 67,
67, 68, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 69, 69, 69,
69, 69, 69, 69, 70, 70, 70, 70,
70, 70, 71, 71, 71, 71, 71, 71,
72, 72, 72, 72, 72, 72, 72, 73,
73, 73, 73, 73, 73, 73, 74, 74,
74, 74, 74, 74, 74, 74, 74, 74,
74, 74, 74, 74, 75, 75, 75, 75,
75, 75, 75, 76, 76, 76, 76, 76,
76, 76, 77, 77, 77, 77, 77, 77,
77, 78, 78, 78, 78, 78, 78, 78,
78, 79, 79, 79, 79, 79, 79, 79,
80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80,
81, 81, 81, 81, 81, 81, 81, 81,
82, 82, 82, 82, 82, 82, 82, 82,
83, 83, 83, 83, 83, 83, 83, 83,
84, 84, 84, 84, 84, 84, 84, 84,
84, 85, 85, 85, 85, 85, 85, 85,
85, 86, 86, 86, 86, 86, 86, 86,
86, 86, 86, 86, 86, 86, 86, 86,
86, 86, 87, 87, 87, 87, 87, 87,
87, 87, 87, 88, 88, 88, 88, 88,
88, 88, 88, 88, 89, 89, 89, 89,
89, 89, 89, 89, 89, 90, 90, 90,
90, 90, 90, 90, 90, 90, 91, 91,
91, 91, 91, 91, 91, 91, 91, 91,
92, 92, 92, 92, 92, 92, 92, 92,
92, 92, 92, 92, 92, 92, 92, 92,
92, 92, 92, 93, 93, 93, 93, 93,
93, 93, 93, 93, 94, 94, 94, 94,
94, 94, 94, 94, 94, 94, 95, 95,
95, 95, 95, 95, 95, 95, 95, 95,
96, 96, 96, 96, 96, 96, 96, 96,
96, 96, 97, 97, 97, 97, 97, 97,
97, 97, 97, 97, 97, 98, 98, 98,
98, 98, 98, 98, 98, 98, 98, 98,
98, 98, 98, 98, 98, 98, 98, 98,
98, 98, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 100, 100, 100, 100,
100, 100, 100, 100, 100, 100, 100, 101,
101, 102, 103, 103, 104, 104, 105, 105,
106, 107, 107, 108, 109, 109, 110, 110,
110, 111, 111, 112, 113, 113, 114, 115,
115, 116, 116, 116, 117, 117, 118, 118,
119, 120, 120, 121, 121, 122, 122, 122,
122, 123, 124, 124, 125, 125, 126, 126,
127, 127, 128, 128, 129, 129, 129, 129,
130, 130, 131, 131, 132, 132, 133, 133,
134, 134, 135, 135, 135, 135, 136, 136,
137, 137, 138, 138, 139, 139, 140, 140,
141, 141, 141, 141, 141, 142, 142, 143,
143, 144, 144, 144, 145, 145, 146, 146,
147, 147, 147, 147, 147, 148, 148, 149,
149, 149, 150, 150, 151, 151, 151, 152,
152, 153, 153, 153, 153, 153, 154, 154,
154, 155, 155, 156, 156, 156, 157, 157,
158, 158, 158, 159, 159, 159, 159, 159,
160, 160, 160, 161, 161, 162, 162, 162,
163, 163, 163, 164, 164, 165, 165, 165,
165, 165, 165, 166, 166, 166, 167, 167,
167, 168, 168, 169, 169, 169, 170, 170,
170, 171, 171, 171, 171, 171, 171, 172,
172, 172, 173, 173, 173, 174, 174, 174,
175, 175, 175, 176, 176, 176, 177, 177,
177, 177, 177, 177, 178, 178, 178, 179,
179, 179, 180, 180, 180, 181, 181, 181,
181, 182, 182, 182, 183, 183, 183, 183,
183, 183, 184, 184, 184, 185, 185, 185,
185, 186, 186, 186, 187, 187, 187, 188,
188, 188, 188, 189, 189, 189, 189, 189,
189, 190, 190, 190, 190, 191, 191, 191,
192, 192, 192, 193, 193, 193, 193, 194,
194, 194, 195, 195, 195, 195, 195, 195,
195, 196, 196, 196, 196, 197, 197, 197,
197, 198, 198, 198, 199, 199, 199, 199,
200, 200, 200, 201, 201, 201, 201, 202,
202, 202, 202, 202, 202, 202, 203, 203,
203, 203, 204, 204, 204, 204, 205, 205,
205, 205, 206, 206, 206, 207, 207, 207,
207, 208, 208, 208, 208, 208, 208, 208,
208, 209, 209, 209, 209, 210, 210, 210,
210, 211, 211, 211, 211, 212, 212, 212,
212, 213, 213, 213, 213, 214, 214, 214,
214, 214, 214, 214, 214, 215, 215, 215,
215, 216, 216, 216, 216, 217, 217, 217,
217, 218, 218, 218, 218, 219, 219, 219,
219, 220, 220, 220, 220, 220, 220, 220,
220, 221, 221, 221, 221, 221, 222, 222,
222, 222, 223, 223, 223, 223, 224, 224,
224, 224, 225, 225, 225, 225, 225, 226,
226, 226, 226, 226, 226, 226, 226, 227,
227, 227, 227, 227, 228, 228, 228, 228,
229, 229, 229, 229, 230, 230, 230, 230,
230, 231, 231, 231, 231, 232, 232, 232,
232, 232, 232, 232, 232, 232, 233, 233,
233, 233, 233, 234, 234, 234, 234, 235
},
};
static struct tegra_dc_nvdisp_cmu default_nvdisp_cmu = {
{},
};
static struct tegra_dc_nvdisp_cmu default_limited_nvdisp_cmu = {
{},
};
#define DSC_MAX_RC_BUF_THRESH_REGS 4
static int dsc_rc_buf_thresh_regs[DSC_MAX_RC_BUF_THRESH_REGS] = {
DC_COM_DSC_RC_BUF_THRESH_0,
DC_COM_DSC_RC_BUF_THRESH_1,
DC_COM_DSC_RC_BUF_THRESH_2,
DC_COM_DSC_RC_BUF_THRESH_3,
};
/*
* Always set the first two values to 0. This is to ensure that RC threshold
* values are programmed in the correct registers.
*/
static int dsc_rc_buf_thresh[] = {
0, 0, 14, 28, 42, 56, 70, 84, 98, 105, 112, 119, 121,
123, 125, 126,
};
#define DSC_MAX_RC_RANGE_CFG_REGS 8
static int dsc_rc_range_config[DSC_MAX_RC_RANGE_CFG_REGS] = {
DC_COM_DSC_RC_RANGE_CFG_0,
DC_COM_DSC_RC_RANGE_CFG_1,
DC_COM_DSC_RC_RANGE_CFG_2,
DC_COM_DSC_RC_RANGE_CFG_3,
DC_COM_DSC_RC_RANGE_CFG_4,
DC_COM_DSC_RC_RANGE_CFG_5,
DC_COM_DSC_RC_RANGE_CFG_6,
DC_COM_DSC_RC_RANGE_CFG_7,
};
static int dsc_rc_ranges_8bpp_8bpc[16][3] = {
{0, 4, 2},
{0, 4, 0},
{1, 5, 0},
{1, 6, -2},
{3, 7, -4},
{3, 7, -6},
{3, 7, -8},
{3, 8, -8},
{3, 9, -8},
{3, 10, -10},
{5, 11, -10},
{5, 12, -12},
{5, 13, -12},
{7, 13, -12},
{13, 15, -12},
{0, 0, 0},
};
static void tegra_dc_t21x_activate_general_channel(struct tegra_dc *dc)
{
tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL);
tegra_dc_readl(dc, DC_CMD_STATE_CONTROL); /* flush */
tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
tegra_dc_readl(dc, DC_CMD_STATE_CONTROL); /* flush */
}
void tegra_dc_activate_general_channel(struct tegra_dc *dc)
{
if (tegra_dc_is_t21x())
tegra_dc_t21x_activate_general_channel(dc);
else
tegra_nvdisp_activate_general_channel(dc);
}
unsigned long tegra_dc_readl_exported(struct tegra_dc *dc, unsigned long reg)
{
return tegra_dc_readl(dc, reg);
}
EXPORT_SYMBOL(tegra_dc_readl_exported);
void tegra_dc_writel_exported(struct tegra_dc *dc,
unsigned long val, unsigned long reg)
{
tegra_dc_writel(dc, val, reg);
}
EXPORT_SYMBOL(tegra_dc_writel_exported);
void tegra_dc_clk_enable(struct tegra_dc *dc)
{
tegra_disp_clk_prepare_enable(dc->clk);
#ifdef CONFIG_TEGRA_CORE_DVFS
tegra_dvfs_set_rate(dc->clk, dc->mode.pclk);
#endif
}
void tegra_dc_clk_disable(struct tegra_dc *dc)
{
tegra_disp_clk_disable_unprepare(dc->clk);
#ifdef CONFIG_TEGRA_CORE_DVFS
tegra_dvfs_set_rate(dc->clk, 0);
#endif
}
void tegra_dc_get(struct tegra_dc *dc)
{
int enable_count = atomic_inc_return(&dc->enable_count);
BUG_ON(enable_count < 1);
if (enable_count == 1) {
tegra_dc_io_start(dc);
/* extra reference to dc clk */
tegra_disp_clk_prepare_enable(dc->clk);
}
}
EXPORT_SYMBOL(tegra_dc_get);
void tegra_dc_put(struct tegra_dc *dc)
{
if (WARN_ONCE(atomic_read(&dc->enable_count) == 0,
"unbalanced clock calls"))
return;
if (atomic_dec_return(&dc->enable_count) == 0) {
/* balance extra dc clk reference */
tegra_disp_clk_disable_unprepare(dc->clk);
tegra_dc_io_end(dc);
}
}
EXPORT_SYMBOL(tegra_dc_put);
unsigned tegra_dc_out_flags_from_dev(struct device *dev)
{
struct platform_device *ndev = NULL;
struct tegra_dc *dc = NULL;
if (dev)
ndev = to_platform_device(dev);
if (ndev)
dc = platform_get_drvdata(ndev);
if (dc)
return dc->out->flags;
else
return 0;
}
EXPORT_SYMBOL(tegra_dc_out_flags_from_dev);
inline bool tegra_dc_in_cmode(struct tegra_dc *dc)
{
u32 nc_mode_flags = (TEGRA_DC_OUT_ONE_SHOT_MODE |
TEGRA_DC_OUT_N_SHOT_MODE |
TEGRA_DC_OUT_ONE_SHOT_LP_MODE);
return !(dc->out->flags & nc_mode_flags);
}
EXPORT_SYMBOL(tegra_dc_in_cmode);
bool tegra_dc_initialized(struct device *dev)
{
struct platform_device *ndev = NULL;
struct tegra_dc *dc = NULL;
if (dev)
ndev = to_platform_device(dev);
if (ndev)
dc = platform_get_drvdata(ndev);
if (dc)
return dc->initialized;
else
return false;
}
EXPORT_SYMBOL(tegra_dc_initialized);
void tegra_dc_hold_dc_out(struct tegra_dc *dc)
{
if (1 == atomic_inc_return(&dc->holding)) {
tegra_dc_get(dc);
if (dc->out_ops && dc->out_ops->hold)
dc->out_ops->hold(dc);
}
}
void tegra_dc_release_dc_out(struct tegra_dc *dc)
{
if (0 == atomic_dec_return(&dc->holding)) {
if (dc->out_ops && dc->out_ops->release)
dc->out_ops->release(dc);
tegra_dc_put(dc);
}
}
bool tegra_dc_hotplug_supported(struct tegra_dc *dc)
{
/* For HDMI|DP, hotplug always supported
* For eDP, hotplug is never supported
* For fake DP, SW hotplug is supported
* Else GPIO# determines if hotplug supported
*/
if (dc->out->type == TEGRA_DC_OUT_HDMI)
return true;
else if (dc->out->type == TEGRA_DC_OUT_DP ||
dc->out->type == TEGRA_DC_OUT_FAKE_DP ||
dc->out->type == TEGRA_DC_OUT_DSI)
return tegra_dc_is_ext_panel(dc);
else
return (dc->out->hotplug_gpio > 0 ? true : false);
}
#define DUMP_REG(a) do { \
snprintf(buff, sizeof(buff), "%-32s\t%03x\t%08lx\n", \
#a, a, tegra_dc_readl(dc, a)); \
print(data, buff); \
} while (0)
void tegra_dc_reg_dump(struct tegra_dc *dc, void *data,
void (* print)(void *data, const char *str))
{
int i;
char buff[256];
const char winname[] = "ABCDHT";
/* for above, see also: DC_CMD_DISPLAY_WINDOW_HEADER and DC_N_WINDOWS */
unsigned long cmd_state;
/* If gated, quietly return. */
if (!tegra_dc_is_powered(dc))
return;
mutex_lock(&dc->lock);
tegra_dc_get(dc);
cmd_state = tegra_dc_readl(dc, DC_CMD_STATE_ACCESS);
tegra_dc_writel(dc, WRITE_MUX_ACTIVE | READ_MUX_ACTIVE,
DC_CMD_STATE_ACCESS);
DUMP_REG(DC_CMD_DISPLAY_COMMAND_OPTION0);
DUMP_REG(DC_CMD_DISPLAY_COMMAND);
DUMP_REG(DC_CMD_SIGNAL_RAISE);
DUMP_REG(DC_CMD_INT_STATUS);
DUMP_REG(DC_CMD_INT_MASK);
DUMP_REG(DC_CMD_INT_ENABLE);
DUMP_REG(DC_CMD_INT_TYPE);
DUMP_REG(DC_CMD_INT_POLARITY);
DUMP_REG(DC_CMD_SIGNAL_RAISE1);
DUMP_REG(DC_CMD_SIGNAL_RAISE2);
DUMP_REG(DC_CMD_SIGNAL_RAISE3);
DUMP_REG(DC_CMD_STATE_ACCESS);
DUMP_REG(DC_CMD_STATE_CONTROL);
DUMP_REG(DC_CMD_DISPLAY_WINDOW_HEADER);
DUMP_REG(DC_CMD_REG_ACT_CONTROL);
DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS0);
DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS1);
DUMP_REG(DC_DISP_DISP_WIN_OPTIONS);
DUMP_REG(DC_DISP_MEM_HIGH_PRIORITY);
DUMP_REG(DC_DISP_MEM_HIGH_PRIORITY_TIMER);
DUMP_REG(DC_DISP_DISP_TIMING_OPTIONS);
DUMP_REG(DC_DISP_REF_TO_SYNC);
DUMP_REG(DC_DISP_SYNC_WIDTH);
DUMP_REG(DC_DISP_BACK_PORCH);
DUMP_REG(DC_DISP_DISP_ACTIVE);
DUMP_REG(DC_DISP_FRONT_PORCH);
DUMP_REG(DC_DISP_H_PULSE0_CONTROL);
DUMP_REG(DC_DISP_H_PULSE0_POSITION_A);
DUMP_REG(DC_DISP_H_PULSE0_POSITION_B);
DUMP_REG(DC_DISP_H_PULSE0_POSITION_C);
DUMP_REG(DC_DISP_H_PULSE0_POSITION_D);
DUMP_REG(DC_DISP_H_PULSE1_CONTROL);
DUMP_REG(DC_DISP_H_PULSE1_POSITION_A);
DUMP_REG(DC_DISP_H_PULSE1_POSITION_B);
DUMP_REG(DC_DISP_H_PULSE1_POSITION_C);
DUMP_REG(DC_DISP_H_PULSE1_POSITION_D);
DUMP_REG(DC_DISP_H_PULSE2_CONTROL);
DUMP_REG(DC_DISP_H_PULSE2_POSITION_A);
DUMP_REG(DC_DISP_H_PULSE2_POSITION_B);
DUMP_REG(DC_DISP_H_PULSE2_POSITION_C);
DUMP_REG(DC_DISP_H_PULSE2_POSITION_D);
DUMP_REG(DC_DISP_V_PULSE0_CONTROL);
DUMP_REG(DC_DISP_V_PULSE0_POSITION_A);
DUMP_REG(DC_DISP_V_PULSE0_POSITION_B);
DUMP_REG(DC_DISP_V_PULSE0_POSITION_C);
DUMP_REG(DC_DISP_V_PULSE1_CONTROL);
DUMP_REG(DC_DISP_V_PULSE1_POSITION_A);
DUMP_REG(DC_DISP_V_PULSE1_POSITION_B);
DUMP_REG(DC_DISP_V_PULSE1_POSITION_C);
DUMP_REG(DC_DISP_V_PULSE2_CONTROL);
DUMP_REG(DC_DISP_V_PULSE2_POSITION_A);
DUMP_REG(DC_DISP_V_PULSE3_CONTROL);
DUMP_REG(DC_DISP_V_PULSE3_POSITION_A);
DUMP_REG(DC_DISP_M0_CONTROL);
DUMP_REG(DC_DISP_M1_CONTROL);
DUMP_REG(DC_DISP_DI_CONTROL);
DUMP_REG(DC_DISP_PP_CONTROL);
DUMP_REG(DC_DISP_PP_SELECT_A);
DUMP_REG(DC_DISP_PP_SELECT_B);
DUMP_REG(DC_DISP_PP_SELECT_C);
DUMP_REG(DC_DISP_PP_SELECT_D);
DUMP_REG(DC_DISP_DISP_CLOCK_CONTROL);
DUMP_REG(DC_DISP_DISP_INTERFACE_CONTROL);
DUMP_REG(DC_DISP_DISP_COLOR_CONTROL);
DUMP_REG(DC_DISP_SHIFT_CLOCK_OPTIONS);
DUMP_REG(DC_DISP_DATA_ENABLE_OPTIONS);
DUMP_REG(DC_DISP_SERIAL_INTERFACE_OPTIONS);
DUMP_REG(DC_DISP_LCD_SPI_OPTIONS);
DUMP_REG(DC_DISP_COLOR_KEY0_LOWER);
DUMP_REG(DC_DISP_COLOR_KEY0_UPPER);
DUMP_REG(DC_DISP_COLOR_KEY1_LOWER);
DUMP_REG(DC_DISP_COLOR_KEY1_UPPER);
DUMP_REG(DC_DISP_CURSOR_FOREGROUND);
DUMP_REG(DC_DISP_CURSOR_BACKGROUND);
DUMP_REG(DC_DISP_CURSOR_START_ADDR);
DUMP_REG(DC_DISP_CURSOR_START_ADDR_NS);
if (tegra_dc_is_t21x()) {
DUMP_REG(DC_DISP_CURSOR_START_ADDR_HI);
DUMP_REG(DC_DISP_CURSOR_START_ADDR_HI_NS);
}
DUMP_REG(DC_DISP_CURSOR_POSITION);
DUMP_REG(DC_DISP_CURSOR_POSITION_NS);
DUMP_REG(DC_DISP_INIT_SEQ_CONTROL);
DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_A);
DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_B);
DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_C);
DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_D);
DUMP_REG(DC_DISP_DC_MCCIF_FIFOCTRL);
DUMP_REG(DC_DISP_MCCIF_DISPLAY0A_HYST);
DUMP_REG(DC_DISP_MCCIF_DISPLAY0B_HYST);
DUMP_REG(DC_DISP_MCCIF_DISPLAY0C_HYST);
DUMP_REG(DC_DISP_DAC_CRT_CTRL);
DUMP_REG(DC_DISP_DISP_MISC_CONTROL);
DUMP_REG(DC_DISP_INTERLACE_CONTROL);
DUMP_REG(DC_DISP_INTERLACE_FIELD2_REF_TO_SYNC);
DUMP_REG(DC_DISP_INTERLACE_FIELD2_SYNC_WIDTH);
DUMP_REG(DC_DISP_INTERLACE_FIELD2_BACK_PORCH);
DUMP_REG(DC_DISP_INTERLACE_FIELD2_FRONT_PORCH);
DUMP_REG(DC_DISP_INTERLACE_FIELD2_DISP_ACTIVE);
DUMP_REG(DC_CMD_DISPLAY_POWER_CONTROL);
DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE2);
DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY2);
DUMP_REG(DC_COM_PIN_OUTPUT_DATA2);
DUMP_REG(DC_COM_PIN_INPUT_ENABLE2);
DUMP_REG(DC_COM_PIN_OUTPUT_SELECT5);
DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS0);
DUMP_REG(DC_DISP_M1_CONTROL);
DUMP_REG(DC_COM_PM1_CONTROL);
DUMP_REG(DC_COM_PM1_DUTY_CYCLE);
DUMP_REG(DC_DISP_SD_CONTROL);
if (tegra_dc_is_t21x()) {
DUMP_REG(DC_COM_CMU_CSC_KRR);
DUMP_REG(DC_COM_CMU_CSC_KGR);
DUMP_REG(DC_COM_CMU_CSC_KBR);
DUMP_REG(DC_COM_CMU_CSC_KRG);
DUMP_REG(DC_COM_CMU_CSC_KGG);
DUMP_REG(DC_COM_CMU_CSC_KBG);
DUMP_REG(DC_COM_CMU_CSC_KRB);
DUMP_REG(DC_COM_CMU_CSC_KGB);
DUMP_REG(DC_COM_CMU_CSC_KBB);
}
for_each_set_bit(i, &dc->valid_windows,
tegra_dc_get_numof_dispwindows()) {
print(data, "\n");
snprintf(buff, sizeof(buff), "WINDOW %c:\n", winname[i]);
print(data, buff);
tegra_dc_writel(dc, WINDOW_A_SELECT << i,
DC_CMD_DISPLAY_WINDOW_HEADER);
DUMP_REG(DC_CMD_DISPLAY_WINDOW_HEADER);
DUMP_REG(DC_WIN_WIN_OPTIONS);
DUMP_REG(DC_WIN_BYTE_SWAP);
DUMP_REG(DC_WIN_BUFFER_CONTROL);
DUMP_REG(DC_WIN_COLOR_DEPTH);
DUMP_REG(DC_WIN_POSITION);
DUMP_REG(DC_WIN_SIZE);
DUMP_REG(DC_WIN_PRESCALED_SIZE);
DUMP_REG(DC_WIN_H_INITIAL_DDA);
DUMP_REG(DC_WIN_V_INITIAL_DDA);
DUMP_REG(DC_WIN_DDA_INCREMENT);
DUMP_REG(DC_WIN_LINE_STRIDE);
DUMP_REG(DC_WIN_BLEND_NOKEY);
DUMP_REG(DC_WIN_BLEND_1WIN);
DUMP_REG(DC_WIN_BLEND_2WIN_X);
DUMP_REG(DC_WIN_BLEND_2WIN_Y);
DUMP_REG(DC_WIN_BLEND_3WIN_XY);
DUMP_REG(DC_WIN_GLOBAL_ALPHA);
DUMP_REG(DC_WINBUF_BLEND_LAYER_CONTROL);
DUMP_REG(DC_WINBUF_START_ADDR);
DUMP_REG(DC_WINBUF_START_ADDR_U);
DUMP_REG(DC_WINBUF_START_ADDR_V);
DUMP_REG(DC_WINBUF_ADDR_H_OFFSET);
DUMP_REG(DC_WINBUF_ADDR_V_OFFSET);
DUMP_REG(DC_WINBUF_START_ADDR_HI);
DUMP_REG(DC_WINBUF_START_ADDR_HI_U);
DUMP_REG(DC_WINBUF_START_ADDR_HI_V);
DUMP_REG(DC_WINBUF_START_ADDR_FIELD2);
DUMP_REG(DC_WINBUF_START_ADDR_FIELD2_U);
DUMP_REG(DC_WINBUF_START_ADDR_FIELD2_V);
DUMP_REG(DC_WINBUF_START_ADDR_FIELD2_HI);
DUMP_REG(DC_WINBUF_START_ADDR_FIELD2_HI_U);
DUMP_REG(DC_WINBUF_START_ADDR_FIELD2_HI_V);
DUMP_REG(DC_WINBUF_ADDR_H_OFFSET_FIELD2);
DUMP_REG(DC_WINBUF_ADDR_V_OFFSET_FIELD2);
DUMP_REG(DC_WINBUF_UFLOW_STATUS);
DUMP_REG(DC_WIN_CSC_YOF);
DUMP_REG(DC_WIN_CSC_KYRGB);
DUMP_REG(DC_WIN_CSC_KUR);
DUMP_REG(DC_WIN_CSC_KVR);
DUMP_REG(DC_WIN_CSC_KUG);
DUMP_REG(DC_WIN_CSC_KVG);
DUMP_REG(DC_WIN_CSC_KUB);
DUMP_REG(DC_WIN_CSC_KVB);
if (tegra_dc_is_t21x()) {
DUMP_REG(DC_WINBUF_CDE_CONTROL);
DUMP_REG(DC_WINBUF_CDE_COMPTAG_BASE_0);
DUMP_REG(DC_WINBUF_CDE_COMPTAG_BASEHI_0);
DUMP_REG(DC_WINBUF_CDE_ZBC_COLOR_0);
DUMP_REG(DC_WINBUF_CDE_SURFACE_OFFSET_0);
DUMP_REG(DC_WINBUF_CDE_CTB_ENTRY_0);
DUMP_REG(DC_WINBUF_CDE_CG_SW_OVR);
DUMP_REG(DC_WINBUF_CDE_PM_CONTROL);
DUMP_REG(DC_WINBUF_CDE_PM_COUNTER);
}
}
tegra_dc_writel(dc, cmd_state, DC_CMD_STATE_ACCESS);
tegra_dc_put(dc);
mutex_unlock(&dc->lock);
}
#undef DUMP_REG
#ifdef DEBUG
static void dump_regs_print(void *data, const char *str)
{
struct tegra_dc *dc = data;
dev_dbg(&dc->ndev->dev, "%s", str);
}
void dump_regs(struct tegra_dc *dc)
{
reg_dump(dc, dc, dump_regs_print);
}
#else /* !DEBUG */
void dump_regs(struct tegra_dc *dc) {}
#endif /* DEBUG */
#ifdef CONFIG_DEBUG_FS
static int dbg_timestamp_show(struct seq_file *s, void *unused)
{
u32 tmp;
u64 timestamp;
u32 frame_cnt;
struct tegra_dc *dc;
dc = s->private;
do {
tmp = (u32)(tegra_dc_readl(dc, DC_COM_RG_DPCA) >> 16);
timestamp = tegra_dc_get_vsync_timestamp(dc);
frame_cnt = tegra_dc_get_frame_cnt(dc);
} while (tmp != frame_cnt);
seq_printf(s, "vsync_timestamp : %llu\n"
"frame_no : %u\n", timestamp, frame_cnt);
return 0;
}
static int dbg_timestamp_open(struct inode *inode, struct file *file)
{
return single_open(file, dbg_timestamp_show, inode->i_private);
}
static const struct file_operations timestamp_fops = {
.open = dbg_timestamp_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static void dbg_regs_print(void *data, const char *str)
{
struct seq_file *s = data;
seq_printf(s, "%s", str);
}
#undef DUMP_REG
static int dbg_dc_show(struct seq_file *s, void *unused)
{
struct tegra_dc *dc = s->private;
reg_dump(dc, s, dbg_regs_print);
return 0;
}
static int dbg_dc_open(struct inode *inode, struct file *file)
{
return single_open(file, dbg_dc_show, inode->i_private);
}
static const struct file_operations regs_fops = {
.open = dbg_dc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int dbg_dc_mode_show(struct seq_file *s, void *unused)
{
struct tegra_dc *dc = s->private;
struct tegra_dc_mode *m;
mutex_lock(&dc->lock);
m = &dc->mode;
seq_printf(s,
"pclk: %d\n"
"h_ref_to_sync: %d\n"
"v_ref_to_sync: %d\n"
"h_sync_width: %d\n"
"v_sync_width: %d\n"
"h_back_porch: %d\n"
"v_back_porch: %d\n"
"h_active: %d\n"
"v_active: %d\n"
"h_front_porch: %d\n"
"v_front_porch: %d\n"
"flags: 0x%x\n"
"stereo_mode: %d\n"
"avi_m: 0x%x\n"
"vmode: 0x%x\n",
m->pclk, m->h_ref_to_sync, m->v_ref_to_sync,
m->h_sync_width, m->v_sync_width,
m->h_back_porch, m->v_back_porch,
m->h_active, m->v_active,
m->h_front_porch, m->v_front_porch,
m->flags, m->stereo_mode, m->avi_m, m->vmode);
mutex_unlock(&dc->lock);
return 0;
}
static int dbg_dc_mode_open(struct inode *inode, struct file *file)
{
return single_open(file, dbg_dc_mode_show, inode->i_private);
}
static const struct file_operations mode_fops = {
.open = dbg_dc_mode_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int dbg_dc_stats_show(struct seq_file *s, void *unused)
{
struct tegra_dc *dc = s->private;
mutex_lock(&dc->lock);
seq_printf(s,
"underflows: %llu\n",
dc->stats.underflows);
if (tegra_dc_is_nvdisplay()) {
seq_printf(s,
"underflow_frames: %llu\n",
dc->stats.underflow_frames);
} else {
seq_printf(s,
"underflows_a: %llu\n"
"underflows_b: %llu\n"
"underflows_c: %llu\n",
dc->stats.underflows_a,
dc->stats.underflows_b,
dc->stats.underflows_c);
seq_printf(s,
"underflows_d: %llu\n"
"underflows_h: %llu\n"
"underflows_t: %llu\n",
dc->stats.underflows_d,
dc->stats.underflows_h,
dc->stats.underflows_t);
}
mutex_unlock(&dc->lock);
return 0;
}
static int dbg_dc_stats_open(struct inode *inode, struct file *file)
{
return single_open(file, dbg_dc_stats_show, inode->i_private);
}
static int dbg_dc_event_inject_show(struct seq_file *s, void *unused)
{
return 0;
}
static ssize_t dbg_dc_event_inject_write(struct file *file,
const char __user *addr, size_t len, loff_t *pos)
{
struct seq_file *m = file->private_data; /* single_open() initialized */
struct tegra_dc *dc = m ? m->private : NULL;
long event;
int ret;
if (!dc)
return -EINVAL;
ret = kstrtol_from_user(addr, len, 10, &event);
if (ret < 0)
return ret;
/*
* ADF has two seperate events for hotplug connect and disconnect.
* We map event 0x0, and 0x1 for them accordingly. For DC_EXT,
* both events map to HOTPLUG.
*/
if (event == 0x0 || event == 0x1) /* TEGRA_DC_EXT_EVENT_HOTPLUG */
tegra_dc_ext_process_hotplug(dc->ndev->id);
else if (event == 0x2) /* TEGRA_DC_EXT_EVENT_BANDWIDTH_DEC */
tegra_dc_ext_process_bandwidth_renegotiate(
dc->ndev->id, NULL);
else {
dev_err(&dc->ndev->dev, "Unknown event 0x%lx\n", event);
return -EINVAL; /* unknown event number */
}
return len;
}
/* Update the strings as dc.h get updated for new output types*/
static const char * const dc_outtype_strings[] = {
"TEGRA_DC_OUT_RGB",
"TEGRA_DC_OUT_HDMI",
"TEGRA_DC_OUT_DSI",
"TEGRA_DC_OUT_DP",
"TEGRA_DC_OUT_LVDS",
"TEGRA_DC_OUT_NVSR_DP",
"TEGRA_DC_OUT_FAKE_DP",
"TEGRA_DC_OUT_FAKE_DSIA",
"TEGRA_DC_OUT_FAKE_DSIB",
"TEGRA_DC_OUT_FAKE_DSI_GANGED",
"TEGRA_DC_OUT_NULL",
"TEGRA_DC_OUT_UNKNOWN"
};
static int dbg_dc_outtype_show(struct seq_file *s, void *unused)
{
struct tegra_dc *dc = s->private;
mutex_lock(&dc->lock);
seq_puts(s, "\n");
seq_printf(s,
"\tDC OUTPUT: \t%s (%d)\n",
dc_outtype_strings[dc->out->type], dc->out->type);
seq_puts(s, "\n");
mutex_unlock(&dc->lock);
return 0;
}