tegrakernel/kernel/nvidia/drivers/video/tegra/dc/of_dc.c

3450 lines
93 KiB
C
Raw Normal View History

2022-02-16 09:13:02 -06:00
/*
* of_dc.c: tegra dc of interface.
*
* Copyright (c) 2013-2019, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#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/clk.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/gpio.h>
#include <linux/i2c.h>
#include <linux/regulator/consumer.h>
#include <linux/of_platform.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/nvhost.h>
#include <linux/timer.h>
#if defined(CONFIG_TRUSTED_LITTLE_KERNEL) || defined(CONFIG_TRUSTY)
#include <linux/ote_protocol.h>
#endif
#ifdef CONFIG_PINCTRL_CONSUMER
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/pinconf-tegra.h>
#endif
#include <video/tegra_hdmi_audio.h>
#include <linux/clk/tegra.h>
#include <linux/platform/tegra/latency_allowance.h>
#include <linux/platform/tegra/mc.h>
#include <soc/tegra/common.h>
#include <linux/version.h>
#include "dc.h"
#include "dc_reg.h"
#include "dc_config.h"
#include "dc_priv.h"
#include "dsi.h"
#include "edid.h"
#include "hdmi2.0.h"
#include "dp.h"
#include "dp_lt.h"
#include "panel/board-panel.h"
#include "panel/tegra-board-id.h"
#include "dc_common.h"
#include "hdmivrr.h"
/* #define OF_DC_DEBUG */
#undef OF_DC_LOG
#ifdef OF_DC_DEBUG
#define OF_DC_LOG(fmt, args...) pr_info("OF_DC_LOG: " fmt, ## args)
#else
#define OF_DC_LOG(fmt, args...)
#endif
static struct regulator *of_hdmi_vddio;
static struct regulator *of_hdmi_dp_reg;
static struct regulator *of_hdmi_pll;
static struct regulator *of_dp_pwr;
static struct regulator *of_dp_pll;
static struct regulator *of_edp_sec_mode;
static struct regulator *of_dp_pad;
static struct regulator *of_dp_hdmi_5v0;
static bool os_l4t;
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 */
{
0,
},
/*lut2*/
{
0,
}
};
struct tegra_panel_ops *tegra_dc_get_panel_ops(struct device_node *panel_np)
{
struct tegra_panel_ops *p_ops = NULL;
if (!panel_np) {
pr_err("%s: invalid input: null panel_np\n", __func__);
return NULL;
}
if (tegra_dc_is_nvdisplay()) {
if (of_device_is_compatible(panel_np, "nvidia,sim-panel")) {
p_ops = &panel_sim_ops;
return p_ops;
}
}
if (of_device_is_compatible(panel_np, "s,wuxga-8-0"))
p_ops = &dsi_s_wuxga_8_0_ops;
else if (of_device_is_compatible(panel_np, "s,wuxga-7-0"))
p_ops = &dsi_s_wuxga_7_0_ops;
else if (of_device_is_compatible(panel_np, "o,720-1280-6-0"))
p_ops = &dsi_o_720p_6_0_ops;
else if (of_device_is_compatible(panel_np, "o,720-1280-6-0-01"))
p_ops = &dsi_o_720p_6_0_ops;
else if (of_device_is_compatible(panel_np, "p,wuxga-10-1"))
p_ops = &dsi_p_wuxga_10_1_ops;
else if (of_device_is_compatible(panel_np, "lg,wxga-7"))
p_ops = &dsi_lgd_wxga_7_0_ops;
else if (of_device_is_compatible(panel_np, "s,wqxga-10-1"))
p_ops = &dsi_s_wqxga_10_1_ops;
else if (of_device_is_compatible(panel_np, "c,wxga-14-0"))
p_ops = &lvds_c_1366_14_ops;
else if (of_device_is_compatible(panel_np, "a,1080p-14-0"))
p_ops = &dsi_a_1080p_14_0_ops;
else if (of_device_is_compatible(panel_np, "j,1440-810-5-8"))
p_ops = &dsi_j_1440_810_5_8_ops;
else if (of_device_is_compatible(panel_np, "j,720p-5-0"))
p_ops = &dsi_j_720p_5_ops;
else if (of_device_is_compatible(panel_np, "l,720p-5-0"))
p_ops = &dsi_l_720p_5_loki_ops;
else if (of_device_is_compatible(panel_np, "a,wuxga-8-0"))
p_ops = &dsi_a_1200_1920_8_0_ops;
else if (of_device_is_compatible(panel_np, "a,wxga-8-0"))
p_ops = &dsi_a_1200_800_8_0_ops;
else if (of_device_is_compatible(panel_np, "i-edp,1080p-11-6"))
p_ops = &edp_i_1080p_11_6_ops;
else if (of_device_is_compatible(panel_np, "a-edp,1080p-14-0"))
p_ops = &edp_a_1080p_14_0_ops;
else if (of_device_is_compatible(panel_np, "s-edp,uhdtv-15-6"))
p_ops = &edp_s_uhdtv_15_6_ops;
else if (of_device_is_compatible(panel_np, "s,4kuhd-5-46"))
p_ops = &dsi_s_4kuhd_5_46_ops;
else if (of_device_is_compatible(panel_np, "b,1440-1600-3-5"))
p_ops = &dsi_b_1440_1600_3_5_ops;
else if (of_device_is_compatible(panel_np, "p-edp,3000-2000-13-5"))
p_ops = &edp_p_3000_2000_13_5_ops;
else if (of_device_is_compatible(panel_np, "null,dsi-hotplug"))
p_ops = &dsi_null_panel_ops;
else
pr_err("%s: unknown panel: %s\n", __func__,
of_node_full_name(panel_np));
return p_ops;
}
int tegra_panel_get_panel_id(const char *comp_str, struct device_node *dnode,
int *panel_id)
{
int err = 0;
struct device_node *node =
of_find_compatible_node(dnode, NULL, comp_str);
if (!node) {
pr_err("%s panel dt support not available\n", comp_str);
err = -ENOENT;
goto fail;
}
err = of_property_read_u32(node, "nvidia,panel-id", panel_id);
fail:
of_node_put(node);
return err;
}
int tegra_panel_regulator_get_dt(struct device *dev,
struct tegra_panel_reg *panel_reg)
{
int err = 0;
panel_reg->vddi_lcd = regulator_get(dev, "dvdd_lcd");
if (IS_ERR_OR_NULL(panel_reg->vddi_lcd)) {
pr_err("vddi_lcd_1v88 regulator get failed\n");
err = PTR_ERR(panel_reg->vddi_lcd);
panel_reg->vddi_lcd = NULL;
goto fail;
}
panel_reg->avdd_lcd = regulator_get(dev, "outp");
if (IS_ERR_OR_NULL(panel_reg->avdd_lcd)) {
pr_err("avdd_lcd_var regulator get failed\n");
err = PTR_ERR(panel_reg->avdd_lcd);
panel_reg->avdd_lcd = NULL;
goto avdd_lcd_var_fail;
}
panel_reg->avee_lcd = regulator_get(dev, "outn");
if (IS_ERR_OR_NULL(panel_reg->avee_lcd)) {
pr_err("avee_lcd_var regulator get failed\n");
err = PTR_ERR(panel_reg->avee_lcd);
panel_reg->avee_lcd = NULL;
goto avee_lcd_var_fail;
}
avee_lcd_var_fail:
if (panel_reg->avdd_lcd) {
regulator_put(panel_reg->avdd_lcd);
panel_reg->avdd_lcd = NULL;
}
avdd_lcd_var_fail:
if (panel_reg->vddi_lcd) {
regulator_put(panel_reg->vddi_lcd);
panel_reg->vddi_lcd = NULL;
}
fail:
return err;
}
void tegra_panel_unregister_ops(struct tegra_dc_out *dc_out)
{
dc_out->enable = NULL;
dc_out->postpoweron = NULL;
dc_out->prepoweroff = NULL;
dc_out->disable = NULL;
dc_out->hotplug_init = NULL;
dc_out->postsuspend = NULL;
dc_out->hotplug_report = NULL;
}
void tegra_panel_register_ops(struct tegra_dc_out *dc_out,
struct tegra_panel_ops *p_ops)
{
dc_out->enable = p_ops->enable;
dc_out->postpoweron = p_ops->postpoweron;
dc_out->prepoweroff = p_ops->prepoweroff;
dc_out->disable = p_ops->disable;
dc_out->hotplug_init = p_ops->hotplug_init;
dc_out->postsuspend = p_ops->postsuspend;
dc_out->hotplug_report = p_ops->hotplug_report;
}
static struct device_node *tegra_dc_get_panel_from_disp_board_id(
struct tegra_dc_platform_data *pdata)
{
struct device_node *panel_np = NULL;
struct board_info display_board;
bool is_dsi_a_1200_1920_8_0 = false;
bool is_dsi_a_1200_800_8_0 = false;
bool is_edp_i_1080p_11_6 = false;
bool is_edp_a_1080p_14_0 = false;
bool is_edp_s_2160p_15_6 = false;
if (!pdata) {
pr_err("%s: invalid input: NULL pdata\n", __func__);
return ERR_PTR(-EINVAL);
}
tegra_get_display_board_info(&display_board);
pr_info("display board info: id 0x%x, fab 0x%x\n",
display_board.board_id, display_board.fab);
switch (display_board.board_id) {
case BOARD_E1627:
case BOARD_E1797:
panel_np = of_find_compatible_node(NULL, NULL,
"p,wuxga-10-1");
break;
case BOARD_E1549:
panel_np = of_find_compatible_node(NULL, NULL,
"lg,wxga-7");
break;
case BOARD_E1639:
case BOARD_E1813:
case BOARD_E2145:
panel_np = of_find_compatible_node(NULL, NULL,
"s,wqxga-10-1");
break;
case BOARD_PM366:
panel_np = of_find_compatible_node(NULL, NULL,
"c,wxga-14-0");
break;
case BOARD_PM354:
panel_np = of_find_compatible_node(NULL, NULL,
"a,1080p-14-0");
break;
case BOARD_E2129:
panel_np = of_find_compatible_node(NULL, NULL,
"j,1440-810-5-8");
break;
case BOARD_E2534:
if (display_board.fab == 0x2) {
panel_np = of_find_compatible_node(NULL, NULL,
"j,720p-5-0");
} else if (display_board.fab == 0x1) {
panel_np = of_find_compatible_node(NULL, NULL,
"j,1440-810-5-8");
} else {
panel_np = of_find_compatible_node(NULL, NULL,
"l,720p-5-0");
}
break;
case BOARD_E1937:
case BOARD_E2149:
is_dsi_a_1200_1920_8_0 = true;
break;
case BOARD_E1807:
is_dsi_a_1200_800_8_0 = true;
break;
case BOARD_P1761:
if (tegra_get_board_panel_id())
is_dsi_a_1200_1920_8_0 = true;
else
is_dsi_a_1200_800_8_0 = true;
break;
case BOARD_PM363:
case BOARD_E1824:
if (of_machine_is_compatible("nvidia,jetson-cv"))
is_edp_s_2160p_15_6 = true;
else if (display_board.sku == 1200)
is_edp_i_1080p_11_6 = true;
else
is_edp_a_1080p_14_0 = true;
break;
case BOARD_E2606:
case BOARD_E2603:
is_edp_a_1080p_14_0 = true;
break;
}
if (is_dsi_a_1200_1920_8_0)
panel_np = of_find_compatible_node(NULL, NULL,
"a,wuxga-8-0");
else if (is_dsi_a_1200_800_8_0)
panel_np = of_find_compatible_node(NULL, NULL,
"a,wxga-8-0");
else if (is_edp_i_1080p_11_6)
panel_np = of_find_compatible_node(NULL, NULL,
"i-edp,1080p-11-6");
else if (is_edp_a_1080p_14_0)
panel_np = of_find_compatible_node(NULL, NULL,
"a-edp,1080p-14-0");
else if (is_edp_s_2160p_15_6)
panel_np = of_find_compatible_node(NULL, NULL,
"s-edp,uhdtv-15-6");
of_node_put(panel_np); /* NULL safe */
return panel_np;
}
static int tegra_dc_parse_panel_ops(struct platform_device *ndev,
struct tegra_dc_platform_data *pdata)
{
int ret = 0;
bool assign_panel_ops = true;
struct device_node *panel_np = NULL;
struct device_node *conn_np = NULL;
struct tegra_panel_ops *panel_ops = NULL;
if (!pdata || !pdata->conn_np) {
dev_err(&ndev->dev, "%s: invalid input: NULL pdata or conn_np\n",
__func__);
ret = -EINVAL;
goto exit;
}
conn_np = pdata->conn_np;
/*
* Note: carrying legacy logic of retrieving panel_np only for
* the first display.
*/
if ((ndev->id == 0) && (tegra_dc_is_t21x())) {
/*
* First select panel based on display board-id. If we don't
* find one then select one specified in device-tree.
*/
panel_np = tegra_dc_get_panel_from_disp_board_id(pdata);
if (!IS_ERR_OR_NULL(panel_np)) {
if (!of_device_is_available(panel_np)) {
dev_err(&ndev->dev,
"panel: %s from disp board is not enabled. Try default panel from DT.\n",
of_node_full_name(panel_np));
panel_np = NULL;
}
} else if (IS_ERR(panel_np)) {
panel_np = NULL;
}
}
/*
* if panel is not selected by display board-id, find panel
* using "nvidia,active-panel" property.
*/
if (!panel_np) {
panel_np = of_parse_phandle(conn_np, "nvidia,active-panel", 0);
if (IS_ERR_OR_NULL(panel_np)) {
dev_err(&ndev->dev, "%s: could not find panel for %s\n",
__func__, of_node_full_name(conn_np));
ret = -ENODEV;
goto exit;
}
}
if (of_device_is_compatible(panel_np, "dsi,1080p") ||
of_device_is_compatible(panel_np, "dsi,2820x720") ||
of_device_is_compatible(panel_np, "dsi,25x16") ||
of_device_is_compatible(panel_np, "s,wuxga-8-0-mods") ||
of_device_is_compatible(panel_np, "dp, display") ||
of_device_is_compatible(panel_np, "hdmi,display"))
assign_panel_ops = false;
if (assign_panel_ops) {
panel_ops = tegra_dc_get_panel_ops(panel_np);
if (!panel_ops) {
ret = -ENODEV;
goto exit;
}
tegra_panel_register_ops(pdata->default_out, panel_ops);
}
if (!of_device_is_available(panel_np)) {
dev_err(&ndev->dev, "%s: panel: %s is not active\n",
__func__, of_node_full_name(panel_np));
if (assign_panel_ops)
tegra_panel_unregister_ops(pdata->default_out);
ret = -ENODEV;
goto exit;
}
pdata->panel_np = panel_np;
exit:
of_node_put(panel_np);
return ret;
}
static int tegra_dc_parse_out_type(struct platform_device *ndev,
struct tegra_dc_platform_data *pdata, bool pdata_initialized)
{
u32 temp;
int ret = 0;
struct device_node *temp_np;
struct device_node *panel_np = pdata->panel_np;
temp_np = of_get_child_by_name(panel_np, "disp-default-out");
if (!temp_np) {
dev_err(&ndev->dev, "mandatory property %s not found\n",
"disp-default-out");
ret = -ENODEV;
goto exit;
}
/* Check for OR out_type from dt when not using crossbar
* or when restoring to boot topology in crossbar
*/
if (!pdata_initialized ||
pdata->default_out->type == TEGRA_DC_TOPOLOGY_RESTORE) {
if (of_property_read_u32(temp_np, "nvidia,out-type", &temp)) {
dev_err(&ndev->dev, "mandatory property %s not found\n",
"nvidia,out-type");
ret = -ENODEV;
goto exit;
}
pdata->default_out->type = (int)temp;
}
if ((pdata->default_out->type < TEGRA_DC_OUT_RGB) ||
(pdata->default_out->type >= TEGRA_DC_OUT_MAX)) {
dev_err(&ndev->dev, "invalid out_type:%d\n",
pdata->default_out->type);
ret = -EINVAL;
goto exit;
}
pdata->def_out_np = temp_np;
exit:
of_node_put(temp_np);
return ret;
}
static bool is_dc_default_out_flag(u32 flag)
{
if ((flag == TEGRA_DC_OUT_HOTPLUG_HIGH) |
(flag == TEGRA_DC_OUT_HOTPLUG_LOW) |
(flag == TEGRA_DC_OUT_NVHDCP_POLICY_ALWAYS_ON) |
(flag == TEGRA_DC_OUT_NVHDCP_POLICY_ON_DEMAND) |
(flag == TEGRA_DC_OUT_CONTINUOUS_MODE) |
(flag == TEGRA_DC_OUT_ONE_SHOT_MODE) |
(flag == TEGRA_DC_OUT_N_SHOT_MODE) |
(flag == TEGRA_DC_OUT_ONE_SHOT_LP_MODE) |
(flag == TEGRA_DC_OUT_INITIALIZED_MODE) |
(flag == TEGRA_DC_OUT_HOTPLUG_WAKE_LP0))
return true;
else
return false;
}
static int parse_disp_default_out(struct platform_device *ndev,
struct tegra_dc_platform_data *pdata)
{
u8 *addr;
u32 temp, u, n_outpins = 0;
int err = 0, hotplug_gpio = 0;
enum of_gpio_flags flags;
const __be32 *p;
const char *temp_str0;
struct property *prop;
struct device_node *conn_np, *out_np;
struct tegra_fb_data *fb;
if (!pdata || !pdata->fb || !pdata->conn_np || !pdata->def_out_np) {
dev_err(&ndev->dev, "NULL pdata, fb, conn_np or def_out_np\n");
return -EINVAL;
}
fb = pdata->fb;
out_np = pdata->def_out_np;
conn_np = pdata->conn_np;
/*
* construct default_out
*/
if (!of_property_read_u32(out_np, "nvidia,out-width", &temp)) {
pdata->default_out->width = (unsigned) temp;
OF_DC_LOG("out_width %d\n", default_out->width);
}
if (!of_property_read_u32(out_np, "nvidia,out-height", &temp)) {
pdata->default_out->height = (unsigned) temp;
OF_DC_LOG("out_height %d\n", default_out->height);
}
if (!of_property_read_u32(out_np, "nvidia,out-rotation", &temp)) {
pdata->default_out->rotation = (unsigned) temp;
OF_DC_LOG("out_rotation %d\n", temp);
}
if (!tegra_platform_is_sim() &&
pdata->default_out->type == TEGRA_DC_OUT_HDMI) {
int id;
struct device_node *ddc_np =
of_parse_phandle(conn_np, "nvidia,ddc-i2c-bus", 0);
if (!ddc_np) {
pdata->default_out->dcc_bus = -1;
pr_warn("error reading %s node\n",
"nvidia,ddc-i2c-bus");
} else {
id = of_alias_get_id(ddc_np, "i2c");
of_node_put(ddc_np);
if (id >= 0) {
pdata->default_out->dcc_bus = id;
OF_DC_LOG("out_dcc bus %d\n", id);
} else {
dev_err(&ndev->dev, "invalid i2c id:%d\n", id);
err = -EINVAL;
goto parse_disp_defout_fail;
}
}
}
hotplug_gpio = of_get_named_gpio_flags(conn_np,
"nvidia,hpd-gpio", 0, &flags);
if (hotplug_gpio >= 0) {
pdata->default_out->hotplug_gpio = hotplug_gpio;
} else {
if (hotplug_gpio == -ENOENT)
dev_info(&ndev->dev, "No hpd-gpio in DT\n");
else
dev_warn(&ndev->dev, "invalid hpd-gpio %d\n",
hotplug_gpio);
if (hotplug_gpio == -EPROBE_DEFER) {
err = -EPROBE_DEFER;
goto parse_disp_defout_fail;
}
}
if (!of_property_read_u32(out_np, "nvidia,out-max-pixclk", &temp)) {
pdata->default_out->max_pixclock = (unsigned)temp;
OF_DC_LOG("%u max_pixclock in pico second unit\n",
pdata->default_out->max_pixclock);
}
if (!of_property_read_u32(out_np, "nvidia,dither", &temp)) {
pdata->default_out->dither = (unsigned)temp;
OF_DC_LOG("dither option %d\n",
pdata->default_out->dither);
}
of_property_for_each_u32(out_np, "nvidia,out-flags", prop, p, u) {
if (!is_dc_default_out_flag(u)) {
dev_err(&ndev->dev, "invalid out-flags:0x%x\n", u);
err = -EINVAL;
goto parse_disp_defout_fail;
}
pdata->default_out->flags |= (unsigned) u;
}
if (!of_property_read_u32(out_np, "nvidia,out-hdcp-policy", &temp)) {
pdata->default_out->hdcp_policy = (unsigned)temp;
OF_DC_LOG("hdcp_policy = %u\n", default_out->hdcp_policy);
} else {
pdata->default_out->hdcp_policy =
#if defined(CONFIG_ANDROID)
TEGRA_DC_HDCP_POLICY_ALWAYS_ON;
#else
TEGRA_DC_HDCP_POLICY_ALWAYS_OFF;
#endif
}
if (tegra_platform_is_sim())
pdata->default_out->hotplug_gpio = -1;
/* if hotplug not supported clear TEGRA_DC_OUT_HOTPLUG_WAKE_LP0 */
if (pdata->default_out->hotplug_gpio < 0)
pdata->default_out->flags &= ~TEGRA_DC_OUT_HOTPLUG_WAKE_LP0;
OF_DC_LOG("default_out flag %u\n", pdata->default_out->flags);
if (!of_property_read_u32(out_np, "nvidia,out-align", &temp)) {
if (temp == TEGRA_DC_ALIGN_MSB) {
OF_DC_LOG("tegra dc align msb\n");
} else if (temp == TEGRA_DC_ALIGN_LSB) {
OF_DC_LOG("tegra dc align lsb\n");
} else {
dev_err(&ndev->dev, "invalid out-align:0x%x\n", temp);
err = -EINVAL;
goto parse_disp_defout_fail;
}
pdata->default_out->align = (unsigned)temp;
}
if (!of_property_read_u32(out_np, "nvidia,out-order", &temp)) {
if (temp == TEGRA_DC_ORDER_RED_BLUE) {
OF_DC_LOG("tegra order red to blue\n");
} else if (temp == TEGRA_DC_ORDER_BLUE_RED) {
OF_DC_LOG("tegra order blue to red\n");
} else {
dev_err(&ndev->dev, "invalid out-order:0x%x\n", temp);
err = -EINVAL;
goto parse_disp_defout_fail;
}
pdata->default_out->order = (unsigned)temp;
}
of_property_for_each_u32(out_np, "nvidia,out-pins", prop, p, u)
n_outpins++;
if ((n_outpins & 0x1) != 0) {
dev_err(&ndev->dev, "should have name, polarity pair!\n");
err = -EINVAL;
goto parse_disp_defout_fail;
}
n_outpins = n_outpins/2;
pdata->default_out->n_out_pins = (unsigned)n_outpins;
if (n_outpins)
pdata->default_out->out_pins = devm_kzalloc(&ndev->dev,
n_outpins * sizeof(struct tegra_dc_out_pin),
GFP_KERNEL);
if (n_outpins && !pdata->default_out->out_pins) {
err = -ENOMEM;
goto parse_disp_defout_fail;
}
addr = (u8 *)pdata->default_out->out_pins;
n_outpins = 0;
of_property_for_each_u32(out_np, "nvidia,out-pins", prop, p, u) {
if ((n_outpins & 0x1) == 0)
((struct tegra_dc_out_pin *)addr)->name = (int)u;
else {
((struct tegra_dc_out_pin *)addr)->pol = (int)u;
addr += sizeof(struct tegra_dc_out_pin);
}
n_outpins++;
}
if (!of_property_read_string(out_np, "nvidia,out-parent-clk",
&temp_str0)) {
pdata->default_out->parent_clk = temp_str0;
OF_DC_LOG("parent clk %s\n", pdata->default_out->parent_clk);
} else {
dev_info(&ndev->dev, "%s: No parent clk. Using default clk\n",
__func__);
}
if (pdata->default_out->type == TEGRA_DC_OUT_HDMI) {
pdata->default_out->depth = 0;
if (tegra_fb_is_console_enabled(pdata)) {
if (!of_property_read_u32(out_np,
"nvidia,out-depth", &temp)) {
pdata->default_out->depth = (unsigned) temp;
OF_DC_LOG("out-depth for HDMI FB console %d\n", temp);
}
}
} else {
if (!of_property_read_u32(out_np, "nvidia,out-depth", &temp)) {
pdata->default_out->depth = (unsigned) temp;
OF_DC_LOG("out-depth for non-HDMI display %d\n", temp);
}
}
if (!of_property_read_u32(out_np, "nvidia,out-hotplug-state", &temp)) {
pdata->default_out->hotplug_state = (unsigned) temp;
OF_DC_LOG("out-hotplug-state %d\n", temp);
}
/*
* construct fb
*/
fb->win = TEGRA_FB_WIN_INVALID; /* set fb->win default */
if (!of_property_read_u32(out_np, "nvidia,out-xres", &temp)) {
fb->xres = (int)temp;
OF_DC_LOG("framebuffer xres %d\n", fb->xres);
}
if (!of_property_read_u32(out_np, "nvidia,out-yres", &temp)) {
fb->yres = (int)temp;
OF_DC_LOG("framebuffer yres %d\n", fb->yres);
}
parse_disp_defout_fail:
return err;
}
static int parse_vrr_settings(struct platform_device *ndev,
struct device_node *np,
struct tegra_vrr *vrr)
{
u32 temp;
if (!of_property_read_u32(np, "nvidia,vrr_min_fps", &temp)) {
vrr->vrr_min_fps = temp;
OF_DC_LOG("vrr_min_fps %u\n", temp);
}
if (!of_property_read_u32(np, "nvidia,frame_len_fluct", &temp)) {
vrr->frame_len_fluct = temp;
OF_DC_LOG("frame_len_fluct %u\n", temp);
} else
vrr->frame_len_fluct = 2000;
if (!of_property_read_u32(np, "nvidia,db_correct_cap", &temp)) {
vrr->db_correct_cap = temp;
OF_DC_LOG("db_correct_cap %u\n", temp);
} else
vrr->db_correct_cap = 0;
if (!of_property_read_u32(np, "nvidia,db_hist_cap", &temp)) {
vrr->db_hist_cap = temp;
OF_DC_LOG("db_hist_cap %u\n", temp);
} else
vrr->db_hist_cap = 0;
if (!of_property_read_u32(np, "nvidia,nvdisp_direct_drive", &temp)) {
vrr->nvdisp_direct_drive = temp;
OF_DC_LOG("nvdisp_direct_drive %u\n", temp);
} else
vrr->nvdisp_direct_drive = 0;
return 0;
}
static void parse_spd_infoframe(struct platform_device *ndev,
struct device_node *np, struct tegra_dc_out *default_out)
{
struct device_node *spd_np = NULL;
struct spd_infoframe *spd;
const char *temp_str0;
u32 temp;
default_out->hdmi_out->spd_infoframe = devm_kzalloc(&ndev->dev,
sizeof(struct spd_infoframe), GFP_KERNEL);
spd = default_out->hdmi_out->spd_infoframe;
strlcpy(spd->vendor_name, SPD_DEFAULT_VENDOR_NAME,
sizeof(spd->vendor_name));
strlcpy(spd->prod_desc, SPD_DEFAULT_PRODUCT_DESC,
sizeof(spd->prod_desc));
spd->source_information = SPD_DEFAULT_SOURCE_INFO;
spd_np = of_get_child_by_name(np, "spd-infoframe");
if (spd_np) {
if (!of_property_read_string(spd_np, "vendor-name",
&temp_str0))
strlcpy(spd->vendor_name, temp_str0,
sizeof(spd->vendor_name));
else
OF_DC_LOG("spd vendor-name is not defined\n");
if (!of_property_read_string(spd_np, "product-description",
&temp_str0))
strlcpy(spd->prod_desc, temp_str0,
sizeof(spd->prod_desc));
else
OF_DC_LOG("spd product-description is not defined\n");
if (!of_property_read_u32(spd_np, "source-information", &temp))
spd->source_information = (u32)temp;
else
OF_DC_LOG("spd source-information is not defined\n");
} else
OF_DC_LOG("%s: No spd-infoframe node\n", __func__);
OF_DC_LOG("spd vendor-name %s\n", spd->vendor_name);
OF_DC_LOG("spd product-description %s\n", spd->prod_desc);
OF_DC_LOG("spd source-information %d\n", spd->source_information);
}
static int parse_modes(struct tegra_dc_out *default_out,
struct device_node *np,
struct tegra_dc_mode *modes)
{
u32 temp;
const struct tegra_dc_out_pin *pins = default_out->out_pins;
int i;
/* {V,H}_REF_TO_SYNC do NOT exist on nvdisplay. */
if (!tegra_dc_is_nvdisplay()) {
if (!of_property_read_u32(np, "nvidia,h-ref-to-sync", &temp)) {
modes->h_ref_to_sync = temp;
} else {
OF_DC_LOG("of h_ref_to_sync %d\n", temp);
goto parse_modes_fail;
}
if (!of_property_read_u32(np, "nvidia,v-ref-to-sync", &temp)) {
modes->v_ref_to_sync = temp;
} else {
OF_DC_LOG("of v_ref_to_sync %d\n", temp);
goto parse_modes_fail;
}
}
if (!of_property_read_u32(np, "clock-frequency", &temp)) {
modes->pclk = temp;
OF_DC_LOG("of pclk %d\n", temp);
} else {
goto parse_modes_fail;
}
if (!of_property_read_u32(np, "hsync-len", &temp)) {
modes->h_sync_width = temp;
} else {
OF_DC_LOG("of h_sync_width %d\n", temp);
goto parse_modes_fail;
}
if (!of_property_read_u32(np, "vsync-len", &temp)) {
modes->v_sync_width = temp;
} else {
OF_DC_LOG("of v_sync_width %d\n", temp);
goto parse_modes_fail;
}
if (!of_property_read_u32(np, "hback-porch", &temp)) {
modes->h_back_porch = temp;
} else {
OF_DC_LOG("of h_back_porch %d\n", temp);
goto parse_modes_fail;
}
if (!of_property_read_u32(np, "vback-porch", &temp)) {
modes->v_back_porch = temp;
} else {
OF_DC_LOG("of v_back_porch %d\n", temp);
goto parse_modes_fail;
}
if (!of_property_read_u32(np, "hactive", &temp)) {
modes->h_active = temp;
} else {
OF_DC_LOG("of h_active %d\n", temp);
goto parse_modes_fail;
}
if (!of_property_read_u32(np, "vactive", &temp)) {
modes->v_active = temp;
} else {
OF_DC_LOG("of v_active %d\n", temp);
goto parse_modes_fail;
}
if (!of_property_read_u32(np, "hfront-porch", &temp)) {
modes->h_front_porch = temp;
} else {
OF_DC_LOG("of h_front_porch %d\n", temp);
goto parse_modes_fail;
}
if (!of_property_read_u32(np, "vfront-porch", &temp)) {
modes->v_front_porch = temp;
} else {
OF_DC_LOG("of v_front_porch %d\n", temp);
goto parse_modes_fail;
}
/* Optional property. Don't fail if not specified */
if (!of_property_read_u32(np, "vmode", &temp)) {
modes->vmode = temp;
}
if (pins && default_out->n_out_pins) {
for (i = 0; i < default_out->n_out_pins; i++) {
switch (pins[i].name) {
case TEGRA_DC_OUT_PIN_DATA_ENABLE:
if (pins[i].pol == TEGRA_DC_OUT_PIN_POL_LOW)
modes->flags |=
TEGRA_DC_MODE_FLAG_NEG_DE;
break;
case TEGRA_DC_OUT_PIN_H_SYNC:
if (pins[i].pol == TEGRA_DC_OUT_PIN_POL_LOW)
modes->flags |=
TEGRA_DC_MODE_FLAG_NEG_H_SYNC;
break;
case TEGRA_DC_OUT_PIN_V_SYNC:
if (pins[i].pol == TEGRA_DC_OUT_PIN_POL_LOW)
modes->flags |=
TEGRA_DC_MODE_FLAG_NEG_V_SYNC;
break;
default:
/* Ignore other pin setting */
break;
}
}
} else {
/* Optional property. Don't fail if not specified */
if (!of_property_read_u32(np, "flags", &temp))
modes->flags = temp;
}
return 0;
parse_modes_fail:
pr_err("a mode parameter parse fail!\n");
return -EINVAL;
}
#if defined(CONFIG_FRAMEBUFFER_CONSOLE)
int parse_fbcon_default_mode(struct device_node *np_target_disp,
struct platform_device *ndev,
struct tegra_dc_platform_data *pdata)
{
struct device_node *fbcon_default_mode_np = NULL;
int err = 0;
fbcon_default_mode_np = of_get_child_by_name(np_target_disp,
"nvidia,fbcon-default-mode");
if (!fbcon_default_mode_np) {
pdata->default_out->fbcon_default_mode = NULL;
} else {
struct tegra_dc_mode fbcon_dc_mode;
memset(&fbcon_dc_mode, 0x0,
sizeof(struct tegra_dc_mode));
pdata->default_out->fbcon_default_mode =
devm_kzalloc(&ndev->dev,
sizeof(struct fb_videomode), GFP_KERNEL);
if (!pdata->default_out->fbcon_default_mode) {
pr_err("%s: not enough memory for fbcon mode\n",
__func__);
err = -ENOMEM;
goto fail_fbcon_parse;
}
err = parse_modes(pdata->default_out,
fbcon_default_mode_np, &fbcon_dc_mode);
if (err) {
pr_err("%s: failed to parse fbcon mode\n", __func__);
goto fail_fbcon_parse;
}
err = tegra_dc_to_fb_videomode(
pdata->default_out->fbcon_default_mode, &fbcon_dc_mode);
if (err) {
pr_err("%s: error converting fbcon mode\n", __func__);
goto fail_fbcon_parse;
}
}
fail_fbcon_parse:
return err;
}
#endif
static int parse_cmu_data(struct device_node *np,
struct tegra_dc_cmu *cmu)
{
u16 *csc_parse;
u16 *addr_cmu_lut1;
u8 *addr_cmu_lut2;
struct property *prop;
const __be32 *p;
u32 u;
int csc_count = 0;
int lut1_count = 0;
int lut2_count = 0;
memcpy(cmu, &default_cmu, sizeof(struct tegra_dc_cmu));
csc_parse = &(cmu->csc.krr);
addr_cmu_lut1 = &(cmu->lut1[0]);
addr_cmu_lut2 = &(cmu->lut2[0]);
of_property_for_each_u32(np, "nvidia,cmu-csc", prop, p, u)
csc_count++;
if (csc_count >
(sizeof(cmu->csc) / sizeof(cmu->csc.krr))) {
pr_err("cmu csc overflow\n");
return -EINVAL;
} else {
of_property_for_each_u32(np,
"nvidia,cmu-csc", prop, p, u) {
OF_DC_LOG("cmu csc 0x%x\n", u);
*(csc_parse++) = (u16)u;
}
}
of_property_for_each_u32(np, "nvidia,cmu-lut1", prop, p, u)
lut1_count++;
if (lut1_count >
(sizeof(cmu->lut1) / sizeof(cmu->lut1[0]))) {
pr_err("cmu lut1 overflow\n");
return -EINVAL;
} else {
of_property_for_each_u32(np, "nvidia,cmu-lut1",
prop, p, u) {
/* OF_DC_LOG("cmu lut1 0x%x\n", u); */
*(addr_cmu_lut1++) = (u16)u;
}
}
of_property_for_each_u32(np, "nvidia,cmu-lut2", prop, p, u)
lut2_count++;
if (lut2_count >
(sizeof(cmu->lut2) / sizeof(cmu->lut2[0]))) {
pr_err("cmu lut2 overflow\n");
return -EINVAL;
} else {
of_property_for_each_u32(np, "nvidia,cmu-lut2",
prop, p, u) {
/* OF_DC_LOG("cmu lut2 0x%x\n", u); */
*(addr_cmu_lut2++) = (u8)u;
}
}
return 0;
}
static int parse_nvdisp_win_csc_data(struct device_node *np,
struct tegra_dc_nvdisp_cmu *nvdisp_cmu)
{
u32 u;
u32 *csc_coeff = &(nvdisp_cmu->panel_csc.r2r);
struct property *prop;
const __be32 *p;
int parsed_coeff_cnt = 0;
int req_coeff_cnt = sizeof(nvdisp_cmu->panel_csc) /
sizeof(nvdisp_cmu->panel_csc.r2r);
req_coeff_cnt -= 1; /* subtract csc_enable */
of_property_for_each_u32(np, "nvidia,panel-csc", prop, p, u)
parsed_coeff_cnt++;
if (parsed_coeff_cnt != req_coeff_cnt) {
pr_err("invalid panel csc matrix. Coeffs req=%d, parsed=%d\n",
req_coeff_cnt, parsed_coeff_cnt);
return -EINVAL;
}
of_property_for_each_u32(np, "nvidia,panel-csc", prop, p, u) {
OF_DC_LOG("panel csc 0x%x\n", u);
*(csc_coeff++) = u;
}
nvdisp_cmu->panel_csc.csc_enable = true;
return 0;
}
static int parse_nvdisp_cmu_data(struct device_node *np,
struct tegra_dc_nvdisp_cmu *nvdisp_cmu)
{
u64 *addr_nvdisp_cmu_lut;
struct property *prop;
const __be32 *p;
u32 u, index = 0, lut_count = 0;
u64 lutvalue = 0;
int err;
addr_nvdisp_cmu_lut = &(nvdisp_cmu->rgb[0]);
of_property_for_each_u32(np, "nvidia,cmu-lut", prop, p, u)
lut_count++;
/* Each Index is being represented by 3 consecutive 16 bit values
* for RED, GREEN and BLUE in DT.
* 1024 LUT indicies will be represented using 3072 entires in DT
*/
if ((lut_count / 3) > (ARRAY_SIZE(nvdisp_cmu->rgb))) {
pr_err("nvdisp_cmu lut overflow\n");
return -EINVAL;
} else {
/* RED, GREEN, BLUE to read and place in a 64bit variable
* to pass to hw register
*/
of_property_for_each_u32(np, "nvidia,cmu-lut",
prop, p, u) {
OF_DC_LOG("0x%x\n", u);
lutvalue = (u64) u;
switch (index % 3) {
case 0: /* red */
*(addr_nvdisp_cmu_lut) = lutvalue;
break;
case 1: /* green */
*(addr_nvdisp_cmu_lut) |= lutvalue << 16;
break;
case 2: /* blue */
*(addr_nvdisp_cmu_lut++) |= lutvalue << 32;
break;
}
index += 1;
}
}
err = parse_nvdisp_win_csc_data(np, nvdisp_cmu);
if (err) {
pr_err("parsing nvdisp_win_csc failed\n");
return err;
}
return 0;
}
struct tegra_dsi_cmd *dsi_parse_cmd_dt(struct device *dev,
const struct device_node *node,
struct property *prop,
u32 n_cmd)
{
struct tegra_dsi_cmd *dsi_cmd = NULL, *temp;
__be32 *prop_val_ptr;
u32 cnt = 0, i = 0;
u8 arg1 = 0, arg2 = 0, arg3 = 0;
bool long_pkt = false;
if (!n_cmd)
return NULL;
if (!prop)
return NULL;
prop_val_ptr = prop->value;
dsi_cmd = devm_kzalloc(dev, sizeof(*dsi_cmd) * n_cmd,
GFP_KERNEL);
if (!dsi_cmd) {
pr_err("dsi: cmd memory allocation failed\n");
return ERR_PTR(-ENOMEM);
}
temp = dsi_cmd;
for (cnt = 0; cnt < n_cmd; cnt++, temp++) {
temp->cmd_type = be32_to_cpu(*prop_val_ptr++);
if ((temp->cmd_type == TEGRA_DSI_PACKET_CMD) ||
(temp->cmd_type ==
TEGRA_DSI_PACKET_VIDEO_VBLANK_CMD)) {
temp->data_id = be32_to_cpu(*prop_val_ptr++);
arg1 = be32_to_cpu(*prop_val_ptr++);
arg2 = be32_to_cpu(*prop_val_ptr++);
prop_val_ptr++; /* skip ecc */
long_pkt = (temp->data_id == DSI_GENERIC_LONG_WRITE ||
temp->data_id == DSI_DCS_LONG_WRITE ||
temp->data_id == DSI_NULL_PKT_NO_DATA ||
temp->data_id == DSI_BLANKING_PKT_NO_DATA) ?
true : false;
if (!long_pkt && (temp->cmd_type ==
TEGRA_DSI_PACKET_VIDEO_VBLANK_CMD))
arg3 = be32_to_cpu(*prop_val_ptr++);
if (long_pkt) {
temp->sp_len_dly.data_len =
(arg2 << NUMOF_BIT_PER_BYTE) | arg1;
temp->pdata = devm_kzalloc(dev,
temp->sp_len_dly.data_len, GFP_KERNEL);
for (i = 0; i < temp->sp_len_dly.data_len; i++)
(temp->pdata)[i] =
be32_to_cpu(*prop_val_ptr++);
prop_val_ptr += 2; /* skip checksum */
} else {
temp->sp_len_dly.sp.data0 = arg1;
temp->sp_len_dly.sp.data1 = arg2;
if (temp->cmd_type ==
TEGRA_DSI_PACKET_VIDEO_VBLANK_CMD)
temp->club_cmd = (bool)arg3;
}
} else if (temp->cmd_type == TEGRA_DSI_DELAY_MS) {
temp->sp_len_dly.delay_ms =
be32_to_cpu(*prop_val_ptr++);
} else if (temp->cmd_type == TEGRA_DSI_DELAY_US) {
temp->sp_len_dly.delay_us =
be32_to_cpu(*prop_val_ptr++);
} else if (temp->cmd_type == TEGRA_DSI_SEND_FRAME) {
temp->sp_len_dly.frame_cnt =
be32_to_cpu(*prop_val_ptr++);
} else if (temp->cmd_type == TEGRA_DSI_GPIO_SET) {
temp->sp_len_dly.gpio =
be32_to_cpu(*prop_val_ptr++);
temp->data_id =
be32_to_cpu(*prop_val_ptr++);
}
}
return dsi_cmd;
}
static struct tegra_dsi_cmd *tegra_dsi_parse_cmd_dt(
struct platform_device *ndev,
const struct device_node *node,
struct property *prop,
u32 n_cmd)
{
struct tegra_dsi_cmd *dsi_cmd = NULL;
dsi_cmd = dsi_parse_cmd_dt(&ndev->dev, node, prop, n_cmd);
return dsi_cmd;
}
static const u32 *tegra_dsi_parse_pkt_seq_dt(struct platform_device *ndev,
struct device_node *node,
struct property *prop)
{
__be32 *prop_val_ptr;
u32 *pkt_seq;
int line, i;
#define LINE_STOP 0xff
if (!prop)
return NULL;
pkt_seq = devm_kzalloc(&ndev->dev,
sizeof(u32) * NUMOF_PKT_SEQ, GFP_KERNEL);
if (!pkt_seq) {
dev_err(&ndev->dev,
"dsi: pkt seq memory allocation failed\n");
return ERR_PTR(-ENOMEM);
}
prop_val_ptr = prop->value;
for (line = 0; line < NUMOF_PKT_SEQ; line += 2) {
/* compute line value from dt line */
for (i = 0;; i += 2) {
u32 cmd = be32_to_cpu(*prop_val_ptr++);
if (cmd == LINE_STOP)
break;
else if (cmd == PKT_LP)
pkt_seq[line] |= PKT_LP;
else {
u32 len = be32_to_cpu(*prop_val_ptr++);
if (i == 0) /* PKT_ID0 */
pkt_seq[line] |=
PKT_ID0(cmd) | PKT_LEN0(len);
if (i == 2) /* PKT_ID1 */
pkt_seq[line] |=
PKT_ID1(cmd) | PKT_LEN1(len);
if (i == 4) /* PKT_ID2 */
pkt_seq[line] |=
PKT_ID2(cmd) | PKT_LEN2(len);
if (i == 6) /* PKT_ID3 */
pkt_seq[line + 1] |=
PKT_ID3(cmd) | PKT_LEN3(len);
if (i == 8) /* PKT_ID4 */
pkt_seq[line + 1] |=
PKT_ID4(cmd) | PKT_LEN4(len);
if (i == 10) /* PKT_ID5 */
pkt_seq[line + 1] |=
PKT_ID5(cmd) | PKT_LEN5(len);
}
}
}
#undef LINE_STOP
return pkt_seq;
}
static int parse_dsi_settings(struct platform_device *ndev,
struct tegra_dc_platform_data *pdata, struct tegra_dc_out *def_out)
{
u32 temp;
int ret = 0;
int dsi_te_gpio = 0;
int bl_name_len = 0;
const __be32 *p;
struct property *prop;
struct tegra_dsi_out *dsi = def_out->dsi;
struct device_node *np_dsi = pdata->conn_np;
struct device_node *np_dsi_panel = pdata->panel_np;
if (!of_property_read_u32(np_dsi, "nvidia,dsi-controller-vs", &temp)) {
dsi->controller_vs = (u8)temp;
if (temp == DSI_VS_0) {
OF_DC_LOG("dsi controller vs DSI_VS_0\n");
} else if (temp == DSI_VS_1) {
OF_DC_LOG("dsi controller vs DSI_VS_1\n");
} else {
dev_err(&ndev->dev, "%s: Invalid version:%d\n",
__func__, temp);
return -EINVAL;
}
}
if (!of_property_read_u32(np_dsi,
"nvidia,enable-hs-clk-in-lp-mode", &temp)) {
dsi->enable_hs_clock_on_lp_cmd_mode = (u8)temp;
OF_DC_LOG("Enable hs clock in lp mode %d\n",
dsi->enable_hs_clock_on_lp_cmd_mode);
}
if (of_property_read_bool(np_dsi,
"nvidia,drm-override-disable")) {
dsi->drm_override_disable = true;
OF_DC_LOG("DRM override disable is true\n");
}
if (of_property_read_bool(np_dsi,
"nvidia,set-max-dsi-timeout")) {
dsi->set_max_timeout = true;
OF_DC_LOG("Set max DSI timeout %d\n",
dsi->set_max_timeout);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-refresh-rate-adj", &temp)) {
dsi->refresh_rate_adj = (u8)temp;
OF_DC_LOG("DSI refresh rate adjustment %d\n",
dsi->refresh_rate_adj);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-n-data-lanes", &temp)) {
dsi->n_data_lanes = (u8)temp;
OF_DC_LOG("n data lanes %d\n", dsi->n_data_lanes);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-video-burst-mode", &temp)) {
dsi->video_burst_mode = (u8)temp;
if (temp == TEGRA_DSI_VIDEO_NONE_BURST_MODE)
OF_DC_LOG("dsi video NON_BURST_MODE\n");
else if (temp == TEGRA_DSI_VIDEO_NONE_BURST_MODE_WITH_SYNC_END)
OF_DC_LOG("dsi video NONE_BURST_MODE_WITH_SYNC_END\n");
else if (temp == TEGRA_DSI_VIDEO_BURST_MODE_LOWEST_SPEED)
OF_DC_LOG("dsi video BURST_MODE_LOWEST_SPEED\n");
else if (temp == TEGRA_DSI_VIDEO_BURST_MODE_LOW_SPEED)
OF_DC_LOG("dsi video BURST_MODE_LOW_SPEED\n");
else if (temp == TEGRA_DSI_VIDEO_BURST_MODE_MEDIUM_SPEED)
OF_DC_LOG("dsi video BURST_MODE_MEDIUM_SPEED\n");
else if (temp == TEGRA_DSI_VIDEO_BURST_MODE_FAST_SPEED)
OF_DC_LOG("dsi video BURST_MODE_FAST_SPEED\n");
else if (temp == TEGRA_DSI_VIDEO_BURST_MODE_FASTEST_SPEED)
OF_DC_LOG("dsi video BURST_MODE_FASTEST_SPEED\n");
else {
pr_err("invalid dsi video burst mode\n");
ret = -EINVAL;
goto parse_dsi_settings_fail;
}
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-pixel-format", &temp)) {
dsi->pixel_format = (u8)temp;
if (temp == TEGRA_DSI_PIXEL_FORMAT_16BIT_P)
OF_DC_LOG("dsi pixel format 16BIT_P\n");
else if (temp == TEGRA_DSI_PIXEL_FORMAT_18BIT_P)
OF_DC_LOG("dsi pixel format 18BIT_P\n");
else if (temp == TEGRA_DSI_PIXEL_FORMAT_18BIT_NP)
OF_DC_LOG("dsi pixel format 18BIT_NP\n");
else if (temp == TEGRA_DSI_PIXEL_FORMAT_24BIT_P)
OF_DC_LOG("dsi pixel format 24BIT_P\n");
else if (temp == TEGRA_DSI_PIXEL_FORMAT_8BIT_DSC)
OF_DC_LOG("dsi pixel format 8BIT_DSC\n");
else if (temp == TEGRA_DSI_PIXEL_FORMAT_12BIT_DSC)
OF_DC_LOG("dsi pixel format 12BIT_DSC\n");
else if (temp == TEGRA_DSI_PIXEL_FORMAT_16BIT_DSC)
OF_DC_LOG("dsi pixel format 16BIT_DSC\n");
else {
pr_err("invalid dsi pixel format\n");
ret = -EINVAL;
goto parse_dsi_settings_fail;
}
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-refresh-rate", &temp)) {
dsi->refresh_rate = (u8)temp;
OF_DC_LOG("dsi refresh rate %d\n", dsi->refresh_rate);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-rated-refresh-rate", &temp)) {
dsi->rated_refresh_rate = (u8)temp;
OF_DC_LOG("dsi rated refresh rate %d\n",
dsi->rated_refresh_rate);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-virtual-channel", &temp)) {
dsi->virtual_channel = (u8)temp;
if (temp == TEGRA_DSI_VIRTUAL_CHANNEL_0)
OF_DC_LOG("dsi virtual channel 0\n");
else if (temp == TEGRA_DSI_VIRTUAL_CHANNEL_1)
OF_DC_LOG("dsi virtual channel 1\n");
else if (temp == TEGRA_DSI_VIRTUAL_CHANNEL_2)
OF_DC_LOG("dsi virtual channel 2\n");
else if (temp == TEGRA_DSI_VIRTUAL_CHANNEL_3)
OF_DC_LOG("dsi virtual channel 3\n");
else {
pr_err("invalid dsi virtual ch\n");
ret = -EINVAL;
goto parse_dsi_settings_fail;
}
}
if (!of_property_read_u32(np_dsi_panel, "nvidia,dsi-instance", &temp)) {
dsi->dsi_instance = (u8)temp;
if (temp == tegra_dc_get_dsi_instance_0())
OF_DC_LOG("dsi instance 0\n");
else if (temp == tegra_dc_get_dsi_instance_1())
OF_DC_LOG("dsi instance 1\n");
else {
pr_err("invalid dsi instance\n");
ret = -EINVAL;
goto parse_dsi_settings_fail;
}
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-panel-reset", &temp)) {
dsi->panel_reset = (u8)temp;
OF_DC_LOG("dsi panel reset %d\n", dsi->panel_reset);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-te-polarity-low", &temp)) {
dsi->te_polarity_low = (u8)temp;
OF_DC_LOG("dsi panel te polarity low %d\n",
dsi->te_polarity_low);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-lp00-pre-panel-wakeup", &temp)) {
dsi->lp00_pre_panel_wakeup = (u8)temp;
OF_DC_LOG("dsi panel lp00 pre panel wakeup %d\n",
dsi->lp00_pre_panel_wakeup);
}
if (of_find_property(np_dsi_panel,
"nvidia,dsi-bl-name", &bl_name_len)) {
dsi->bl_name = devm_kzalloc(&ndev->dev,
sizeof(u8) * bl_name_len, GFP_KERNEL);
if (!of_property_read_string(np_dsi_panel,
"nvidia,dsi-bl-name",
(const char **)&dsi->bl_name))
OF_DC_LOG("dsi panel bl name %s\n", dsi->bl_name);
else {
pr_err("dsi error parsing bl name\n");
devm_kfree(&ndev->dev, dsi->bl_name);
}
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-ganged-type", &temp)) {
dsi->ganged_type = (u8)temp;
OF_DC_LOG("dsi ganged_type %d\n", dsi->ganged_type);
/* Set pixel width to 1 by default for even-odd split */
if (dsi->ganged_type == TEGRA_DSI_GANGED_SYMMETRIC_EVEN_ODD)
dsi->even_odd_split_width = 1;
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-even-odd-pixel-width", &temp)) {
dsi->even_odd_split_width = temp;
OF_DC_LOG("dsi pixel width for even/odd split %d\n",
dsi->even_odd_split_width);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-ganged-overlap", &temp)) {
dsi->ganged_overlap = (u16)temp;
OF_DC_LOG("dsi ganged overlap %d\n", dsi->ganged_overlap);
if (!dsi->ganged_type)
pr_warn("specified ganged overlap, but no ganged type\n");
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-ganged-swap-links", &temp)) {
dsi->ganged_swap_links = (bool)temp;
OF_DC_LOG("dsi ganged swapped links %d\n",
dsi->ganged_swap_links);
if (!dsi->ganged_type)
pr_warn("specified ganged swapped links, but no ganged type\n");
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-ganged-write-to-all-links", &temp)) {
dsi->ganged_write_to_all_links = (bool)temp;
OF_DC_LOG("dsi ganged write to both links %d\n",
dsi->ganged_write_to_all_links);
if (!dsi->ganged_type)
pr_warn("specified ganged write to all links, but no ganged type\n");
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-split-link-type", &temp)) {
dsi->split_link_type = (u8)temp;
OF_DC_LOG("dsi split link type %d\n", dsi->split_link_type);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-suspend-aggr", &temp)) {
dsi->suspend_aggr = (u8)temp;
OF_DC_LOG("dsi suspend_aggr %d\n", dsi->suspend_aggr);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-edp-bridge", &temp)) {
dsi->dsi2edp_bridge_enable = (bool)temp;
OF_DC_LOG("dsi2edp_bridge_enabled %d\n",
dsi->dsi2edp_bridge_enable);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-lvds-bridge", &temp)) {
dsi->dsi2lvds_bridge_enable = (bool)temp;
OF_DC_LOG("dsi-lvds_bridge_enabled %d\n",
dsi->dsi2lvds_bridge_enable);
}
dsi_te_gpio = of_get_named_gpio(np_dsi_panel, "nvidia,dsi-te-gpio", 0);
if (gpio_is_valid(dsi_te_gpio)) {
dsi->te_gpio = dsi_te_gpio;
OF_DC_LOG("dsi te_gpio %d\n", dsi_te_gpio);
}
of_property_for_each_u32(np_dsi_panel, "nvidia,dsi-dpd-pads",
prop, p, temp) {
dsi->dpd_dsi_pads |= (u32)temp;
OF_DC_LOG("dpd_dsi_pads %u\n", dsi->dpd_dsi_pads);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-power-saving-suspend", &temp)) {
dsi->power_saving_suspend = (bool)temp;
OF_DC_LOG("dsi power saving suspend %d\n",
dsi->power_saving_suspend);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-ulpm-not-support", &temp)) {
dsi->ulpm_not_supported = (bool)temp;
OF_DC_LOG("dsi ulpm_not_supported %d\n",
dsi->ulpm_not_supported);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-video-data-type", &temp)) {
dsi->video_data_type = (u8)temp;
if (temp == TEGRA_DSI_VIDEO_TYPE_VIDEO_MODE)
OF_DC_LOG("dsi video type VIDEO_MODE\n");
else if (temp == TEGRA_DSI_VIDEO_TYPE_COMMAND_MODE)
OF_DC_LOG("dsi video type COMMAND_MODE\n");
else {
pr_err("invalid dsi video data type\n");
ret = -EINVAL;
goto parse_dsi_settings_fail;
}
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-video-clock-mode", &temp)) {
dsi->video_clock_mode = (u8)temp;
if (temp == TEGRA_DSI_VIDEO_CLOCK_CONTINUOUS)
OF_DC_LOG("dsi video clock mode CONTINUOUS\n");
else if (temp == TEGRA_DSI_VIDEO_CLOCK_TX_ONLY)
OF_DC_LOG("dsi video clock mode TX_ONLY\n");
else {
pr_err("invalid dsi video clk mode\n");
ret = -EINVAL;
goto parse_dsi_settings_fail;
}
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-n-init-cmd", &temp)) {
dsi->n_init_cmd = (u16)temp;
OF_DC_LOG("dsi n_init_cmd %d\n",
dsi->n_init_cmd);
}
dsi->dsi_init_cmd =
tegra_dsi_parse_cmd_dt(ndev, np_dsi_panel,
of_find_property(np_dsi_panel,
"nvidia,dsi-init-cmd", NULL),
dsi->n_init_cmd);
if (dsi->n_init_cmd &&
IS_ERR_OR_NULL(dsi->dsi_init_cmd)) {
dev_err(&ndev->dev,
"dsi: copy init cmd from dt failed\n");
ret = -EINVAL;
goto parse_dsi_settings_fail;
};
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-n-postvideo-cmd", &temp)) {
dsi->n_postvideo_cmd = (u16)temp;
OF_DC_LOG("dsi n_postvideo_cmd %d\n",
dsi->n_postvideo_cmd);
}
dsi->dsi_postvideo_cmd =
tegra_dsi_parse_cmd_dt(ndev, np_dsi_panel,
of_find_property(np_dsi_panel,
"nvidia,dsi-postvideo-cmd", NULL),
dsi->n_postvideo_cmd);
if (dsi->n_postvideo_cmd &&
IS_ERR_OR_NULL(dsi->dsi_postvideo_cmd)) {
dev_err(&ndev->dev,
"dsi: copy postvideo cmd from dt failed\n");
goto parse_dsi_settings_fail;
};
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-n-suspend-cmd", &temp)) {
dsi->n_suspend_cmd = (u16)temp;
OF_DC_LOG("dsi n_suspend_cmd %d\n",
dsi->n_suspend_cmd);
}
dsi->dsi_suspend_cmd =
tegra_dsi_parse_cmd_dt(ndev, np_dsi_panel,
of_find_property(np_dsi_panel,
"nvidia,dsi-suspend-cmd", NULL),
dsi->n_suspend_cmd);
if (dsi->n_suspend_cmd &&
IS_ERR_OR_NULL(dsi->dsi_suspend_cmd)) {
dev_err(&ndev->dev,
"dsi: copy suspend cmd from dt failed\n");
ret = -EINVAL;
goto parse_dsi_settings_fail;
};
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-n-early-suspend-cmd", &temp)) {
dsi->n_early_suspend_cmd = (u16)temp;
OF_DC_LOG("dsi n_early_suspend_cmd %d\n",
dsi->n_early_suspend_cmd);
}
dsi->dsi_early_suspend_cmd =
tegra_dsi_parse_cmd_dt(ndev, np_dsi_panel,
of_find_property(np_dsi_panel,
"nvidia,dsi-early-suspend-cmd", NULL),
dsi->n_early_suspend_cmd);
if (dsi->n_early_suspend_cmd &&
IS_ERR_OR_NULL(dsi->dsi_early_suspend_cmd)) {
dev_err(&ndev->dev,
"dsi: copy early suspend cmd from dt failed\n");
ret = -EINVAL;
goto parse_dsi_settings_fail;
};
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-suspend-stop-stream-late", &temp)) {
dsi->suspend_stop_stream_late = (bool)temp;
OF_DC_LOG("suspend stop stream late %d\n",
dsi->suspend_stop_stream_late);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-n-late-resume-cmd", &temp)) {
dsi->n_late_resume_cmd = (u16)temp;
OF_DC_LOG("dsi n_late_resume_cmd %d\n",
dsi->n_late_resume_cmd);
}
dsi->dsi_late_resume_cmd =
tegra_dsi_parse_cmd_dt(ndev, np_dsi_panel,
of_find_property(np_dsi_panel,
"nvidia,dsi-late-resume-cmd", NULL),
dsi->n_late_resume_cmd);
if (dsi->n_late_resume_cmd &&
IS_ERR_OR_NULL(dsi->dsi_late_resume_cmd)) {
dev_err(&ndev->dev,
"dsi: copy late resume cmd from dt failed\n");
ret = -EINVAL;
goto parse_dsi_settings_fail;
};
dsi->pkt_seq =
tegra_dsi_parse_pkt_seq_dt(ndev, np_dsi_panel,
of_find_property(np_dsi_panel,
"nvidia,dsi-pkt-seq", NULL));
if (IS_ERR(dsi->pkt_seq)) {
dev_err(&ndev->dev, "dsi pkt seq from dt fail\n");
ret = -EINVAL;
goto parse_dsi_settings_fail;
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-hsdexit", &temp)) {
dsi->phy_timing.t_hsdexit_ns = (u16)temp;
OF_DC_LOG("phy t_hsdexit_ns %d\n",
dsi->phy_timing.t_hsdexit_ns);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-hstrail", &temp)) {
dsi->phy_timing.t_hstrail_ns = (u16)temp;
OF_DC_LOG("phy t_hstrail_ns %d\n",
dsi->phy_timing.t_hstrail_ns);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-datzero", &temp)) {
dsi->phy_timing.t_datzero_ns = (u16)temp;
OF_DC_LOG("phy t_datzero_ns %d\n",
dsi->phy_timing.t_datzero_ns);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-hsprepare", &temp)) {
dsi->phy_timing.t_hsprepare_ns = (u16)temp;
OF_DC_LOG("phy t_hsprepare_ns %d\n",
dsi->phy_timing.t_hsprepare_ns);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-clktrail", &temp)) {
dsi->phy_timing.t_clktrail_ns = (u16)temp;
OF_DC_LOG("phy t_clktrail_ns %d\n",
dsi->phy_timing.t_clktrail_ns);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-clkpost", &temp)) {
dsi->phy_timing.t_clkpost_ns = (u16)temp;
OF_DC_LOG("phy t_clkpost_ns %d\n",
dsi->phy_timing.t_clkpost_ns);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-clkzero", &temp)) {
dsi->phy_timing.t_clkzero_ns = (u16)temp;
OF_DC_LOG("phy t_clkzero_ns %d\n",
dsi->phy_timing.t_clkzero_ns);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-tlpx", &temp)) {
dsi->phy_timing.t_tlpx_ns = (u16)temp;
OF_DC_LOG("phy t_tlpx_ns %d\n",
dsi->phy_timing.t_tlpx_ns);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-clkprepare", &temp)) {
dsi->phy_timing.t_clkprepare_ns = (u16)temp;
OF_DC_LOG("phy t_clkprepare_ns %d\n",
dsi->phy_timing.t_clkprepare_ns);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-clkpre", &temp)) {
dsi->phy_timing.t_clkpre_ns = (u16)temp;
OF_DC_LOG("phy t_clkpre_ns %d\n",
dsi->phy_timing.t_clkpre_ns);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-wakeup", &temp)) {
dsi->phy_timing.t_wakeup_ns = (u16)temp;
OF_DC_LOG("phy t_wakeup_ns %d\n",
dsi->phy_timing.t_wakeup_ns);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-taget", &temp)) {
dsi->phy_timing.t_taget_ns = (u16)temp;
OF_DC_LOG("phy t_taget_ns %d\n",
dsi->phy_timing.t_taget_ns);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-tasure", &temp)) {
dsi->phy_timing.t_tasure_ns = (u16)temp;
OF_DC_LOG("phy t_tasure_ns %d\n",
dsi->phy_timing.t_tasure_ns);
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-tago", &temp)) {
dsi->phy_timing.t_tago_ns = (u16)temp;
OF_DC_LOG("phy t_tago_ns %d\n",
dsi->phy_timing.t_tago_ns);
}
if (!of_find_property(np_dsi_panel,
"nvidia,dsi-boardinfo", NULL)) {
of_property_read_u32_index(np_dsi_panel,
"nvidia,dsi-boardinfo", 0,
&dsi->boardinfo.platform_boardid);
of_property_read_u32_index(np_dsi_panel,
"nvidia,dsi-boardinfo", 1,
&dsi->boardinfo.platform_boardversion);
of_property_read_u32_index(np_dsi_panel,
"nvidia,dsi-boardinfo", 2,
&dsi->boardinfo.display_boardid);
of_property_read_u32_index(np_dsi_panel,
"nvidia,dsi-boardinfo", 3,
&dsi->boardinfo.display_boardversion);
OF_DC_LOG("boardinfo platform_boardid = %d \
platform_boardversion = %d \
display_boardid = %d \
display_boardversion = %d\n",
dsi->boardinfo.platform_boardid,
dsi->boardinfo.platform_boardversion,
dsi->boardinfo.display_boardid,
dsi->boardinfo.display_boardversion);
}
if (of_property_read_bool(np_dsi_panel,
"nvidia,enable-link-compression"))
def_out->dsc_en = true;
if (of_property_read_bool(np_dsi_panel,
"nvidia,enable-dual-dsc"))
def_out->dual_dsc_en = true;
if (of_property_read_bool(np_dsi_panel,
"nvidia,enable-block-pred"))
def_out->en_block_pred = true;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,slice-height", &temp))
def_out->slice_height = (u32)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,num-of-slices", &temp))
def_out->num_of_slices = (u8)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,comp-rate", &temp))
def_out->dsc_bpp = (u8)temp;
if (of_property_read_bool(np_dsi, "nvidia,dsi-csi-loopback")) {
dsi->dsi_csi_loopback = 1;
OF_DC_LOG("DSI CSI loopback %d\n",
dsi->dsi_csi_loopback);
}
parse_dsi_settings_fail:
return ret;
}
static int parse_lt_setting(struct device_node *np, u8 *addr)
{
u32 u, temp;
int i = 0;
const __be32 *p;
struct property *prop;
struct tegra_dc_dp_lt_settings *lt_setting_addr;
int n_drive_current =
sizeof(lt_setting_addr->drive_current)/
sizeof(lt_setting_addr->drive_current[0]);
int n_lane_preemphasis =
sizeof(lt_setting_addr->lane_preemphasis)/
sizeof(lt_setting_addr->lane_preemphasis[0]);
int n_post_cursor =
sizeof(lt_setting_addr->post_cursor)/
sizeof(lt_setting_addr->post_cursor[0]);
lt_setting_addr = (struct tegra_dc_dp_lt_settings *)addr;
of_property_for_each_u32(np, "nvidia,drive-current", prop, p, u) {
lt_setting_addr->drive_current[i] = (u32)u;
i++;
}
if (n_drive_current != i)
return -EINVAL;
i = 0;
of_property_for_each_u32(np, "nvidia,lane-preemphasis", prop, p, u) {
lt_setting_addr->lane_preemphasis[i] = (u32)u;
i++;
}
if (n_lane_preemphasis != i)
return -EINVAL;
i = 0;
of_property_for_each_u32(np, "nvidia,post-cursor", prop, p, u) {
lt_setting_addr->post_cursor[i] = (u32)u;
i++;
}
if (n_post_cursor != i)
return -EINVAL;
if (!of_property_read_u32(np, "nvidia,tx-pu", &temp)) {
lt_setting_addr->tx_pu = (u32)temp;
OF_DC_LOG("tx_pu %d\n", temp);
}
if (!of_property_read_u32(np, "nvidia,load-adj", &temp)) {
lt_setting_addr->load_adj = (u32)temp;
OF_DC_LOG("load_adj %d\n", temp);
}
return 0;
}
static const char * const lt_data_name[] = {
"tegra-dp-vs-regs",
"tegra-dp-pe-regs",
"tegra-dp-pc-regs",
"tegra-dp-tx-pu",
};
static const char * const lt_data_child_name[] = {
"pc2_l0",
"pc2_l1",
"pc2_l2",
"pc2_l3",
};
/*
* get lt_data from platform device tree
*/
static int parse_lt_data(struct device_node *np,
struct tegra_dp_out *dpout)
{
int i, j, k, m, n;
struct device_node *entry;
struct property *prop;
const __be32 *p;
u32 u;
u32 temp[10];
for (i = 0; i < dpout->n_lt_data; i++) {
entry = of_get_child_by_name(np, lt_data_name[i]);
if (!entry) {
pr_info("%s: lt-data node has no child node named %s\n",
__func__, lt_data_name[i]);
return -1;
}
dpout->lt_data[i].name = lt_data_name[i];
for (j = 0; j < 4; j++) {
k = 0;
memset(temp, 0, sizeof(temp));
of_property_for_each_u32(entry,
lt_data_child_name[j] , prop, p, u) {
temp[k++] = (u32)u;
}
k = 0;
for (m = 0; m < 4; m++) {
for (n = 0; n < 4-m; n++) {
dpout->lt_data[i].data[j][m][n] = temp[k++];
}
}
}
of_node_put(entry);
}
return 0;
}
/*
* get SoC lt_data from header file, dp_lt.h
*/
static int set_lt_data(struct tegra_dp_out *dpout)
{
int j, m, n;
for (j = 0; j < 4; j++) {
for (m = 0; m < 4; m++) {
for (n = 0; n < 4-m; n++) {
if (tegra_dc_is_nvdisplay())
dpout->lt_data[DP_VS].data[j][m][n] =
tegra_dp_vs_regs_nvdisplay[j][m][n];
else
dpout->lt_data[DP_VS].data[j][m][n] =
tegra_dp_vs_regs[j][m][n];
dpout->lt_data[DP_PE].data[j][m][n] = tegra_dp_pe_regs[j][m][n];
dpout->lt_data[DP_PC].data[j][m][n] = tegra_dp_pc_regs[j][m][n];
dpout->lt_data[DP_TX_PU].data[j][m][n] = tegra_dp_tx_pu[j][m][n];
}
}
}
return 0;
}
static int parse_dp_settings(struct platform_device *ndev,
struct tegra_dc_platform_data *pdata, struct tegra_dc_out *def_out)
{
u8 *addr;
u32 temp;
int ret = 0;
struct device_node *np_dp_lt_set = NULL;
struct device_node *np_lt_data = NULL;
struct device_node *entry = NULL;
struct tegra_dp_out *dpout = def_out->dp_out;
struct device_node *np_dp_panel = pdata->panel_np;
dpout->pc2_disabled = of_property_read_bool(np_dp_panel,
"nvidia,pc2-disabled");
np_dp_lt_set = of_get_child_by_name(np_dp_panel, "dp-lt-settings");
if (!np_dp_lt_set) {
dev_info(&ndev->dev, "%s: No dp-lt-settings node\n", __func__);
} else {
int n_lt_settings = of_get_child_count(np_dp_lt_set);
if (!n_lt_settings) {
dev_info(&ndev->dev, "lt-settings node has no child node\n");
} else {
dpout->n_lt_settings = n_lt_settings;
dpout->lt_settings = devm_kzalloc(&ndev->dev,
n_lt_settings *
sizeof(struct tegra_dc_dp_lt_settings),
GFP_KERNEL);
if (!dpout->lt_settings)
goto parse_dp_settings_fail;
addr = (u8 *)dpout->lt_settings;
for_each_child_of_node(np_dp_lt_set, entry) {
ret = parse_lt_setting(entry, addr);
if (ret)
goto parse_dp_settings_fail;
addr += sizeof(struct tegra_dc_dp_lt_settings);
}
}
}
dpout->n_lt_data = 4;
dpout->lt_data = devm_kzalloc(&ndev->dev,
dpout->n_lt_data * sizeof(struct tegra_dc_lt_data), GFP_KERNEL);
if (!dpout->lt_data)
goto parse_dp_settings_fail;
np_lt_data = of_get_child_by_name(np_dp_panel, "lt-data");
if (!np_lt_data || !of_get_child_count(np_lt_data)) {
dev_info(&ndev->dev, "No lt-data, using default setting\n");
set_lt_data(dpout);
} else {
ret = parse_lt_data(np_lt_data, dpout);
if (ret)
goto parse_dp_settings_fail;
}
if (!of_property_read_u32(np_dp_panel, "nvidia,tx-pu-disable", &temp)) {
dpout->tx_pu_disable = (bool)temp;
OF_DC_LOG("tx_pu_disable %d\n", dpout->tx_pu_disable);
}
if (!of_property_read_u32(np_dp_panel, "nvidia,lanes", &temp)) {
dpout->lanes = (int)temp;
OF_DC_LOG("lanes %d\n", dpout->lanes);
} else {
dpout->lanes = 4;
OF_DC_LOG("default lanes %d\n", dpout->lanes);
}
dpout->enhanced_framing_disable = of_property_read_bool(np_dp_panel,
"nvidia,enhanced-framing-disable");
OF_DC_LOG("enhanced-framing-disable %d\n",
!!dpout->enhanced_framing_disable);
if (!of_property_read_u32(np_dp_panel, "nvidia,link-bw", &temp)) {
dpout->link_bw = (u8)temp;
OF_DC_LOG("link_bw %d\n", dpout->link_bw);
} else {
dpout->link_bw = (tegra_dc_is_t19x()) ?
NV_DPCD_MAX_LINK_BANDWIDTH_VAL_8_10_GBPS :
NV_DPCD_MAX_LINK_BANDWIDTH_VAL_5_40_GBPS;
OF_DC_LOG("default link_bw %d\n", dpout->link_bw);
}
of_node_put(np_lt_data);
of_node_put(np_dp_lt_set);
return ret;
parse_dp_settings_fail:
of_node_put(np_lt_data);
of_node_put(np_dp_lt_set);
devm_kfree(&ndev->dev, dpout->lt_data);
devm_kfree(&ndev->dev, dpout->lt_settings);
return ret;
}
static int dc_dp_out_enable(struct device *dev)
{
int ret = 0;
if (!of_dp_pwr) {
of_dp_pwr = devm_regulator_get(dev, "vdd-dp-pwr");
if (IS_ERR(of_dp_pwr)) {
dev_warn(dev,
"dp: couldn't get regulator vdd-dp-pwr\n");
ret = PTR_ERR(of_dp_pwr);
of_dp_pwr = NULL;
}
}
if (!of_dp_pll) {
of_dp_pll = devm_regulator_get(dev, "avdd-dp-pll");
if (IS_ERR(of_dp_pll)) {
dev_warn(dev,
"dp: couldn't get regulator avdd-dp-pll\n");
ret = PTR_ERR(of_dp_pll);
of_dp_pll = NULL;
}
}
if (!of_edp_sec_mode) {
of_edp_sec_mode = devm_regulator_get(dev, "vdd-edp-sec-mode");
if (IS_ERR(of_edp_sec_mode)) {
dev_warn(dev,
"dp: couldn't get regulator vdd-edp-sec-mode\n");
ret = PTR_ERR(of_edp_sec_mode);
of_edp_sec_mode = NULL;
}
}
if (!of_dp_pad) {
of_dp_pad = devm_regulator_get(dev, "vdd-dp-pad");
if (IS_ERR(of_dp_pad)) {
dev_warn(dev,
"dp: couldn't get regulator vdd-dp-pad\n");
ret = PTR_ERR(of_dp_pad);
of_dp_pad = NULL;
}
}
if (of_dp_pwr) {
ret = regulator_enable(of_dp_pwr);
if (ret < 0)
dev_err(dev,
"dp: couldn't enable regulator vdd-dp-pwr\n");
}
if (of_dp_pll) {
ret = regulator_enable(of_dp_pll);
if (ret < 0)
dev_err(dev,
"dp: couldn't enable regulator vdd-dp-pll\n");
}
if (of_edp_sec_mode) {
ret = regulator_enable(of_edp_sec_mode);
if (ret < 0)
dev_err(dev,
"dp: couldn't enable regulator vdd-edp-sec-mode\n");
}
if (of_dp_pad) {
ret = regulator_enable(of_dp_pad);
if (ret < 0)
dev_err(dev,
"dp: couldn't enable regulator vdd-dp-pad\n");
}
return ret;
}
static int dc_dp_out_disable(struct device *dev)
{
if (of_dp_pwr) {
regulator_disable(of_dp_pwr);
}
if (of_dp_pll) {
regulator_disable(of_dp_pll);
}
if (of_edp_sec_mode) {
regulator_disable(of_edp_sec_mode);
}
if (of_dp_pad) {
regulator_disable(of_dp_pad);
}
return 0;
}
static int dc_dp_out_hotplug_init(struct device *dev)
{
int err = 0;
int gpio;
struct tegra_dc *dc;
dc = tegra_get_dc_from_dev(dev);
if (!dc) {
err = -ENODEV;
goto fail;
}
/* hotplug pin should be in spio mode */
gpio = dc->pdata->default_out->hotplug_gpio;
if (gpio_is_valid(gpio)) {
err = gpio_request(gpio, "temp_request");
if (!err)
gpio_free(gpio);
}
/*
* DP doesn't actually need this regulator.
* Instead dp needs gpio coupled with this regulator.
* pmic has already requested this gpio
* Required for level translator logic.
*/
if (!of_dp_hdmi_5v0) {
of_dp_hdmi_5v0 = devm_regulator_get(dev, "vdd_hdmi_5v0");
if (IS_ERR(of_dp_hdmi_5v0)) {
err = PTR_ERR(of_dp_hdmi_5v0);
dev_info(dev, "%s: couldn't get regulator %s\n",
__func__, "vdd_hdmi_5v0");
of_dp_hdmi_5v0 = NULL;
}
}
if (of_dp_hdmi_5v0) {
err = regulator_enable(of_dp_hdmi_5v0);
if (err < 0)
dev_err(dev, "%s: couldn't enable regulator %s\n",
__func__, "vdd_hdmi_5v0");
}
fail:
return err;
}
static int dc_dp_out_postsuspend(void)
{
if (of_dp_hdmi_5v0) {
regulator_disable(of_dp_hdmi_5v0);
}
return 0;
}
static int dc_hdmi_out_enable(struct device *dev)
{
int err = 0;
if (!of_hdmi_dp_reg) {
of_hdmi_dp_reg = devm_regulator_get(dev, "avdd_hdmi");
if (IS_ERR(of_hdmi_dp_reg)) {
dev_err(dev, "%s: couldn't get regulator %s\n",
__func__, "avdd_hdmi");
of_hdmi_dp_reg = NULL;
err = PTR_ERR(of_hdmi_dp_reg);
goto dc_hdmi_out_en_fail;
}
}
err = regulator_enable(of_hdmi_dp_reg);
if (err < 0) {
dev_err(dev, "%s: couldn't enable regulator %s\n",
__func__, "avdd_hdmi");
goto dc_hdmi_out_en_fail;
}
if (!of_hdmi_pll) {
of_hdmi_pll = devm_regulator_get(dev, "avdd_hdmi_pll");
if (IS_ERR(of_hdmi_pll)) {
dev_err(dev, "%s: couldn't get regulator %s\n",
__func__, "avdd_hdmi_pll");
of_hdmi_pll = NULL;
of_hdmi_dp_reg = NULL;
err = PTR_ERR(of_hdmi_pll);
goto dc_hdmi_out_en_fail;
}
}
err = regulator_enable(of_hdmi_pll);
if (err < 0) {
dev_err(dev, "%s: couldn't enable regulator %s\n",
__func__, "avdd_hdmi_pll");
goto dc_hdmi_out_en_fail;
}
dc_hdmi_out_en_fail:
return err;
}
static int dc_hdmi_out_disable(struct device *dev)
{
struct platform_device *ndev = NULL;
struct tegra_hdmi *hdmi = NULL;
struct tegra_dc *dc = NULL;
if (!dev)
return -EINVAL;
ndev = to_platform_device(dev);
dc = platform_get_drvdata(ndev);
hdmi = tegra_dc_get_outdata(dc);
/* Do not disable regulator when device is shutting down */
if (hdmi->device_shutdown)
return 0;
if (of_hdmi_dp_reg) {
regulator_disable(of_hdmi_dp_reg);
}
if (of_hdmi_pll) {
regulator_disable(of_hdmi_pll);
}
return 0;
}
static int dc_hdmi_hotplug_init(struct device *dev)
{
int err = 0;
if (!of_hdmi_vddio) {
of_hdmi_vddio = devm_regulator_get(dev, "vdd_hdmi_5v0");
if (IS_ERR(of_hdmi_vddio)) {
err = PTR_ERR(of_hdmi_vddio);
dev_err(dev, "%s: couldn't get regulator %s, %d\n",
__func__, "vdd_hdmi_5v0", err);
of_hdmi_vddio = NULL;
goto dc_hdmi_hotplug_init_fail;
}
}
err = regulator_enable(of_hdmi_vddio);
if (err < 0) {
dev_err(dev, "%s: couldn't enable regulator %s, %d\n",
__func__, "vdd_hdmi_5v0", err);
goto dc_hdmi_hotplug_init_fail;
}
dc_hdmi_hotplug_init_fail:
return err;
}
static int dc_hdmi_postsuspend(void)
{
if (of_hdmi_vddio) {
regulator_disable(of_hdmi_vddio);
}
return 0;
}
static bool is_dc_default_flag(u32 flag)
{
if (flag == (flag &
(TEGRA_DC_FLAG_ENABLED |
TEGRA_DC_FLAG_SET_EARLY_MODE |
TEGRA_DC_FLAG_FBCON_DISABLED)
))
return true;
else
return false;
}
static int parse_imp_win_values(struct device_node *settings_np,
struct platform_device *pdev,
struct tegra_nvdisp_imp_settings *imp_settings,
int num_entries)
{
u8 win_ids_arr[DC_N_WINDOWS];
s8 thread_group_arr[DC_N_WINDOWS];
u16 fetch_slots_arr[DC_N_WINDOWS];
u32 pipe_meter_arr[DC_N_WINDOWS];
u64 dvfs_watermark_arr[DC_N_WINDOWS];
u64 mempool_entries_arr[DC_N_WINDOWS];
int i, ret = 0;
if (WARN_ON(DC_N_WINDOWS < num_entries)) {
dev_err(&pdev->dev, "invalid num_entries\n");
return -EINVAL;
}
ret = of_property_read_u8_array(settings_np,
"nvidia,imp_win_mapping",
win_ids_arr, num_entries);
if (ret) {
dev_err(&pdev->dev, "Can't parse nvidia,imp_win_mapping\n");
return ret;
}
ret = of_property_read_u16_array(settings_np,
"nvidia,win_fetch_meter_slots",
fetch_slots_arr, num_entries);
if (ret) {
dev_err(&pdev->dev,
"Can't parse nvidia,win_fetch_meter_slots\n");
return ret;
}
ret = of_property_read_u64_array(settings_np,
"nvidia,win_dvfs_watermark_values",
dvfs_watermark_arr, num_entries);
if (ret) {
dev_err(&pdev->dev,
"Can't parse nvidia,win_dvfs_watermark_values\n");
return ret;
}
ret = of_property_read_u32_array(settings_np,
"nvidia,win_pipe_meter_values",
pipe_meter_arr, num_entries);
if (ret) {
dev_err(&pdev->dev,
"Can't parse nvidia,win_pipe_meter_values\n");
return ret;
}
ret = of_property_read_u64_array(settings_np,
"nvidia,win_mempool_buffer_entries",
mempool_entries_arr, num_entries);
if (ret) {
dev_err(&pdev->dev,
"Can't parse nvidia,win_mempool_buffer_entries\n");
return ret;
}
ret = of_property_read_u8_array(settings_np,
"nvidia,win_thread_groups",
thread_group_arr, num_entries);
if (ret) {
dev_err(&pdev->dev, "Can't parse nvidia,win_thread_groups\n");
return ret;
}
for (i = 0; i < imp_settings->num_heads; i++) {
struct tegra_nvdisp_imp_head_settings *head_settings;
struct tegra_dc_ext_nvdisp_imp_win_entries *win_entries;
int j;
head_settings = &imp_settings->head_settings[i];
win_entries = head_settings->win_entries;
for (j = 0; j < num_entries; j++) {
struct tegra_dc_ext_nvdisp_imp_win_entries *win_entry;
win_entry = &win_entries[j];
win_entry->id = win_ids_arr[j];
win_entry->thread_group = thread_group_arr[j];
win_entry->fetch_slots = fetch_slots_arr[j];
win_entry->pipe_meter = pipe_meter_arr[j];
win_entry->dvfs_watermark = dvfs_watermark_arr[j];
win_entry->mempool_entries = mempool_entries_arr[j];
}
}
return ret;
}
static int parse_imp_cursor_values(struct device_node *settings_np,
struct platform_device *pdev,
struct tegra_nvdisp_imp_settings *imp_settings,
int num_entries)
{
u32 max_heads = tegra_dc_get_numof_dispheads();
u8 ctrl_num_arr[max_heads];
u16 fetch_slots_arr[max_heads];
u32 pipe_meter_arr[max_heads];
u64 dvfs_watermark_arr[max_heads];
u64 mempool_entries_arr[max_heads];
int ret = 0, i;
ret = of_property_read_u8_array(settings_np,
"nvidia,imp_head_mapping",
ctrl_num_arr, num_entries);
if (ret) {
dev_err(&pdev->dev, "Can't parse nvidia,imp_head_mapping\n");
return ret;
}
ret = of_property_read_u16_array(settings_np,
"nvidia,cursor_fetch_meter_slots",
fetch_slots_arr, num_entries);
if (ret) {
dev_err(&pdev->dev,
"Can't parse nvidia,cursor_fetch_meter_slots\n");
return ret;
}
ret = of_property_read_u64_array(settings_np,
"nvidia,cursor_dvfs_watermark_values",
dvfs_watermark_arr, num_entries);
if (ret) {
dev_err(&pdev->dev,
"Can't parse nvidia,cursor_dvfs_watermark_values\n");
return ret;
}
ret = of_property_read_u32_array(settings_np,
"nvidia,cursor_pipe_meter_values",
pipe_meter_arr, num_entries);
if (ret) {
dev_err(&pdev->dev,
"Can't parse nvidia,cursor_pipe_meter_values\n");
return ret;
}
ret = of_property_read_u64_array(settings_np,
"nvidia,cursor_mempool_buffer_entries",
mempool_entries_arr, num_entries);
if (ret) {
dev_err(&pdev->dev,
"Can't parse nvidia,cursor_mempool_buffer_entries\n");
return ret;
}
for (i = 0; i < num_entries; i++) {
struct tegra_nvdisp_imp_head_settings *head_settings;
struct tegra_dc_ext_nvdisp_imp_head_entries *head_entries;
head_settings = &imp_settings->head_settings[i];
head_entries = &head_settings->entries;
head_entries->ctrl_num = ctrl_num_arr[i];
head_entries->curs_fetch_slots = fetch_slots_arr[i];
head_entries->curs_pipe_meter = pipe_meter_arr[i];
head_entries->curs_dvfs_watermark = dvfs_watermark_arr[i];
head_entries->curs_mempool_entries = mempool_entries_arr[i];
}
return ret;
}
static void dealloc_imp_table_settings(
struct tegra_nvdisp_imp_settings *imp_settings)
{
int i;
for (i = 0; i < imp_settings->num_heads; i++) {
struct tegra_nvdisp_imp_head_settings *head_settings;
head_settings = &imp_settings->head_settings[i];
if (head_settings->num_wins > 0)
kfree(head_settings->win_entries);
}
if (imp_settings->num_heads > 0)
kfree(imp_settings->head_settings);
}
static void dealloc_imp_table(struct nvdisp_imp_table *imp_table)
{
int i;
if (!imp_table)
return;
for (i = 0; i < imp_table->num_settings; i++)
dealloc_imp_table_settings(&imp_table->settings[i]);
}
static int alloc_imp_table_settings(struct platform_device *pdev,
struct tegra_nvdisp_imp_settings *imp_settings,
int num_head_entries, int num_win_entries)
{
int j;
if (num_head_entries <= 0 || num_win_entries <= 0) {
dev_err(&pdev->dev,
"No IMP table heads and/or wins found\n");
return -EINVAL;
}
imp_settings->head_settings = devm_kzalloc(&pdev->dev,
sizeof(*(imp_settings->head_settings)) * num_head_entries,
GFP_KERNEL);
if (!imp_settings->head_settings)
return -ENOMEM;
imp_settings->num_heads = num_head_entries;
for (j = 0; j < num_head_entries; j++) {
struct tegra_nvdisp_imp_head_settings *head_settings;
head_settings = &imp_settings->head_settings[j];
head_settings->win_entries = devm_kzalloc(&pdev->dev,
sizeof(*(head_settings->win_entries)) * num_win_entries,
GFP_KERNEL);
if (!head_settings->win_entries)
return -ENOMEM;
head_settings->num_wins = num_win_entries;
}
return 0;
}
static int tegra_dc_parse_imp_data(struct device_node *imp_np,
struct platform_device *pdev,
struct nvdisp_imp_table *imp_table)
{
struct device_node *settings_np = NULL;
struct tegra_nvdisp_imp_settings *imp_settings;
int ret = 0, i = 0;
u32 num_settings = 0;
ret = of_property_read_u32(imp_np, "num_settings", &num_settings);
if (ret || !num_settings) {
dev_err(&pdev->dev, "No IMP table settings found\n");
return -ENOENT;
}
imp_table->settings = devm_kzalloc(&pdev->dev,
sizeof(*(imp_table->settings)) * num_settings,
GFP_KERNEL);
if (!imp_table->settings)
return -ENOMEM;
imp_table->num_settings = num_settings;
for (i = 0; i < num_settings; i++) {
struct tegra_dc_ext_nvdisp_imp_global_entries *global_entries;
char settings_name[CHAR_BUF_SIZE_MAX] = {0};
int num_head_entries, num_win_entries;
snprintf(settings_name, sizeof(settings_name),
"disp_imp_settings_%d", i);
settings_np = of_get_child_by_name(imp_np, settings_name);
if (!settings_np) {
dev_err(&pdev->dev, "Can't find %s\n", settings_name);
ret = -ENOENT;
goto fail_parse_imp_table;
}
num_head_entries = of_property_count_u8_elems(settings_np,
"nvidia,imp_head_mapping");
num_win_entries = of_property_count_u8_elems(settings_np,
"nvidia,imp_win_mapping");
imp_settings = &imp_table->settings[i];
ret = alloc_imp_table_settings(pdev, imp_settings,
num_head_entries, num_win_entries);
if (ret)
goto fail_parse_imp_table;
global_entries = &imp_settings->global_entries;
ret = of_property_read_u64(settings_np,
"nvidia,total_disp_bw_with_catchup",
&global_entries->total_iso_bw_with_catchup_kBps);
if (ret) {
dev_err(&pdev->dev,
"Can't parse nvidia,total_disp_bw_with_catchup\n");
goto fail_parse_imp_table;
}
ret = of_property_read_u64(settings_np,
"nvidia,total_disp_bw_without_catchup",
&global_entries->total_iso_bw_without_catchup_kBps);
if (ret) {
dev_err(&pdev->dev,
"Can't parse nvidia,total_disp_bw_without_catchup\n");
goto fail_parse_imp_table;
}
ret = of_property_read_u64(settings_np,
"nvidia,disp_emc_floor",
&global_entries->emc_floor_hz);
if (ret) {
dev_err(&pdev->dev,
"Can't parse nvidia,disp_emc_floor\n");
goto fail_parse_imp_table;
}
ret = of_property_read_u64(settings_np,
"nvidia,disp_min_hubclk",
&global_entries->min_hubclk_hz);
if (ret) {
dev_err(&pdev->dev,
"Can't parse nvidia,disp_min_hubclk\n");
goto fail_parse_imp_table;
}
ret = of_property_read_u16(settings_np,
"nvidia,total_win_fetch_slots",
&global_entries->total_win_fetch_slots);
if (ret) {
dev_err(&pdev->dev,
"Can't parse nvidia,total_win_fetch_slots\n");
goto fail_parse_imp_table;
}
ret = of_property_read_u16(settings_np,
"nvidia,total_cursor_fetch_slots",
&global_entries->total_curs_fetch_slots);
if (ret) {
dev_err(&pdev->dev,
"Can't parse nvidia,total_cursor_fetch_slots\n");
goto fail_parse_imp_table;
}
ret = parse_imp_cursor_values(settings_np, pdev, imp_settings,
num_head_entries);
if (ret)
goto fail_parse_imp_table;
ret = parse_imp_win_values(settings_np, pdev, imp_settings,
num_win_entries);
if (ret)
goto fail_parse_imp_table;
of_node_put(settings_np);
}
return ret;
fail_parse_imp_table:
of_node_put(settings_np);
dealloc_imp_table(imp_table);
kfree(imp_table->settings);
return ret;
}
int of_tegra_get_fb_resource(struct device_node *np,
struct resource *res, const char *reg_name)
{
int index;
unsigned int flags;
u64 size;
u64 *addrp;
struct device_node *fb_node = of_parse_phandle(np, "fb_reserved", 0);
if (fb_node == NULL)
goto fail;
index = of_property_match_string(fb_node, "reg-names", reg_name);
if (index < 0)
goto fail;
addrp = (u64 *)of_get_address(fb_node, index, &size, &flags);
if (addrp == NULL)
goto fail;
res->start = *addrp;
if (res->start)
res->end = res->start + size - 1;
else
res->end = 0;
return 0;
fail:
res->start = 0;
res->end = 0;
return -EINVAL;
}
static int tegra_dc_register_typec_edev(struct platform_device *ndev,
struct device_node *sor_np,
struct extcon_dev **typec_edev_ptr)
{
struct extcon_dev *typec_edev;
char port_name[CHAR_BUF_SIZE_MAX] = {0};
u8 typec_port;
if (of_property_read_u8(sor_np, "nvidia,typec-port", &typec_port))
return 0;
snprintf(port_name, sizeof(port_name), "typec%u", typec_port);
typec_edev = extcon_get_extcon_dev_by_cable(&ndev->dev, port_name);
if (!typec_edev) {
dev_err(&ndev->dev, "typec extcon dev is NULL\n");
return -ENODEV;
} else if (IS_ERR(typec_edev)) {
if (PTR_ERR(typec_edev) != -EPROBE_DEFER)
dev_err(&ndev->dev,
"Couldn't find typec extcon dev: %ld\n",
PTR_ERR(typec_edev));
return PTR_ERR(typec_edev);
}
*typec_edev_ptr = typec_edev;
return 0;
}
struct tegra_dc_platform_data *of_dc_parse_platform_data(
struct platform_device *ndev, struct tegra_dc_platform_data *boot_pdata)
{
u32 temp;
int err = 0;
#if defined(CONFIG_TRUSTED_LITTLE_KERNEL) || defined(CONFIG_TRUSTY)
int check_val;
#endif
const __be32 *p;
struct tegra_dc_platform_data *pdata;
struct device_node *np = ndev->dev.of_node;
struct device_node *timings_np = NULL;
struct device_node *vrr_np = NULL;
struct device_node *np_target_disp = NULL;
struct device_node *entry = NULL;
struct property *prop;
struct tegra_dc_out *def_out;
bool pdata_initialized = false;
bool restore_topology = false;
struct tegra_dc *dc = NULL;
char dc_or_conn_node[CHAR_BUF_SIZE_MAX];
struct device_node *cmu_np = NULL;
struct device_node *cmu_adbRGB_np = NULL;
struct extcon_dev *typec_edev = NULL;
/*
* Memory for pdata, pdata->default_out, pdata->fb
* need to be allocated in default
* since it is expected data for these needs to be
* parsed from DTB.
*/
if (boot_pdata) {
pdata_initialized = true;
pdata = boot_pdata;
dc = tegra_get_dc_from_dev(&ndev->dev);
if (dc && dc->current_topology.conn_inst ==
TEGRA_DC_TOPOLOGY_RESTORE)
restore_topology = true;
} else {
pdata = devm_kzalloc(&ndev->dev,
sizeof(struct tegra_dc_platform_data), GFP_KERNEL);
if (!pdata) {
dev_err(&ndev->dev, "not enough memory\n");
err = -ENOMEM;
goto fail_parse;
}
pdata->default_out = devm_kzalloc(&ndev->dev,
sizeof(struct tegra_dc_out), GFP_KERNEL);
if (!pdata->default_out) {
dev_err(&ndev->dev, "not enough memory\n");
err = -ENOMEM;
goto fail_parse;
}
pdata->fb = devm_kzalloc(&ndev->dev,
sizeof(struct tegra_fb_data), GFP_KERNEL);
if (!pdata->fb) {
dev_err(&ndev->dev, "not enough memory\n");
err = -ENOMEM;
goto fail_parse;
}
}
def_out = pdata->default_out;
if (!of_property_read_u32(np, "nvidia,frame_lock_enable", &temp)) {
pdata->frame_lock_enable = (bool)temp;
OF_DC_LOG("nvidia,frame_lock_enable%d\n", pdata->frame_lock_enable);
}
/* Check for connector during crossbar */
if (pdata_initialized && !restore_topology) {
switch (def_out->type) {
case TEGRA_DC_OUT_FAKE_DP:
case TEGRA_DC_OUT_HDMI:
case TEGRA_DC_OUT_DP:
if (dc->current_topology.conn_inst == 0) {
pdata->conn_np =
of_find_node_by_path("/host1x/sor");
} else {
snprintf(dc_or_conn_node, 13, "/host1x/sor%d",
dc->current_topology.conn_inst);
pdata->conn_np =
of_find_node_by_path(dc_or_conn_node);
}
break;
case TEGRA_DC_OUT_DSI:
pdata->conn_np = of_find_node_by_path("/host1x/dsi");
break;
break;
}
} else {
pdata->conn_np = of_parse_phandle(np, "nvidia,dc-connector", 0);
}
if (IS_ERR_OR_NULL(pdata->conn_np)) {
dev_err(&ndev->dev, "mandatory prop:%s not defined\n",
"nvidia,dc-connector");
err = PTR_ERR(pdata->conn_np);
goto fail_parse;
}
err = tegra_dc_register_typec_edev(ndev, pdata->conn_np, &typec_edev);
if (err)
goto fail_parse;
if (!of_property_read_u32(np, "nvidia,dc-ctrlnum", &temp)) {
pdata->ctrl_num = (unsigned long)temp;
OF_DC_LOG("dc controller index %lu\n", pdata->ctrl_num);
} else {
dev_err(&ndev->dev, "mandatory property %s not found\n",
"nvidia,dc-ctrlnum");
goto fail_parse;
}
dev_info(&ndev->dev, "disp%d connected to head%d->%s\n", ndev->id,
(int)pdata->ctrl_num, of_node_full_name(pdata->conn_np));
/* Check for panel node during crossbar */
if (pdata_initialized && !restore_topology) {
pdata->panel_np = NULL;
if (def_out->type == TEGRA_DC_OUT_HDMI)
pdata->panel_np = of_get_child_by_name(pdata->conn_np,
"hdmi-display");
else if ((def_out->type == TEGRA_DC_OUT_DP) ||
(def_out->type == TEGRA_DC_OUT_FAKE_DP))
pdata->panel_np = of_get_child_by_name(pdata->conn_np,
"dp-display");
if (!pdata->panel_np) {
pr_warn("crossbar: no panel found for out_type %d\n",
def_out->type);
err = -ENODEV;
}
} else {
err = tegra_dc_parse_panel_ops(ndev, pdata);
if (err) {
dev_err(&ndev->dev, "err:%d parsing panel_ops\n", err);
goto fail_parse;
}
}
err = tegra_dc_parse_out_type(ndev, pdata, pdata_initialized);
if (err) {
dev_err(&ndev->dev, "err:%d parsing out_type\n", err);
goto fail_parse;
}
if (!of_property_read_u32(np, "nvidia,fb-bpp", &temp)) {
pdata->fb->bits_per_pixel = (int)temp;
OF_DC_LOG("fb bpp %d\n", pdata->fb->bits_per_pixel);
} else {
dev_err(&ndev->dev, "mandatory prop:%s not defined\n",
"nvidia,fb-bpp");
err = -ENOENT;
goto fail_parse;
}
if (!of_property_read_u32(np, "nvidia,fbmem-size", &temp)) {
pdata->fb->fbmem_size = temp;
OF_DC_LOG("fbmem size %u\n", pdata->fb->fbmem_size);
}
if (!of_property_read_u32(np, "nvidia,fb-flags", &temp)) {
if (temp == TEGRA_FB_FLIP_ON_PROBE) {
OF_DC_LOG("fb flip on probe\n");
} else if (temp == 0) {
OF_DC_LOG("do not flip fb on probe time\n");
} else {
dev_err(&ndev->dev, "invalid fb-flags:0x%x\n", temp);
err = -EINVAL;
goto fail_parse;
}
pdata->fb->flags = (unsigned long)temp;
}
if (of_property_read_bool(np, "nvidia,50hz-ss-war")) {
pdata->plld2_ss_enable = true;
OF_DC_LOG("dc plld2 ss enabled - %d\n", pdata->plld2_ss_enable);
} else {
pdata->plld2_ss_enable = false;
}
if (def_out->type == TEGRA_DC_OUT_DSI) {
/* TODO: Add crossbar implementation for DSI */
def_out->dsi = devm_kzalloc(&ndev->dev,
sizeof(struct tegra_dsi_out), GFP_KERNEL);
if (!def_out->dsi) {
err = -ENOMEM;
goto fail_parse;
}
err = parse_dsi_settings(ndev, pdata, def_out);
if (err) {
dev_err(&ndev->dev, "dsi parsing failed:%d\n", err);
goto fail_parse;
}
np_target_disp = pdata->panel_np;
} else if (def_out->type == TEGRA_DC_OUT_DP ||
def_out->type == TEGRA_DC_OUT_FAKE_DP) {
def_out->dp_out = devm_kzalloc(&ndev->dev,
sizeof(struct tegra_dp_out), GFP_KERNEL);
if (!def_out->dp_out) {
err = -ENOMEM;
goto fail_parse;
}
err = parse_dp_settings(ndev, pdata, def_out);
if (err) {
dev_err(&ndev->dev, "dp parsing failed:%d\n", err);
goto fail_parse;
}
np_target_disp = pdata->panel_np;
if (!of_property_read_u32(np_target_disp,
"nvidia,hdmi-fpd-bridge", &temp)) {
def_out->dp_out->hdmi2fpd_bridge_enable = (bool)temp;
OF_DC_LOG("hdmi2fpd_bridge_enabled %d\n",
def_out->hdmi_out->
hdmi2fpd_bridge_enable);
}
if (!of_property_read_u32(np_target_disp,
"nvidia,edp-lvds-bridge", &temp)) {
def_out->dp_out->edp2lvds_bridge_enable = (bool)temp;
OF_DC_LOG("edp2lvds_bridge_enabled %d\n",
def_out->dp_out->
edp2lvds_bridge_enable);
}
if (!of_property_read_u32(np_target_disp,
"nvidia,edp-lvds-i2c-bus-no", &temp)) {
def_out->dp_out->edp2lvds_i2c_bus_no = temp;
OF_DC_LOG("edp2lvds_i2c_bus_no %d\n",
def_out->dp_out->
edp2lvds_i2c_bus_no);
}
def_out->dp_out->typec_ecable.edev = typec_edev;
/* enable/disable ops for DP monitors */
if (!def_out->enable && !def_out->disable) {
def_out->enable = dc_dp_out_enable;
def_out->disable = dc_dp_out_disable;
def_out->hotplug_init = dc_dp_out_hotplug_init;
def_out->postsuspend = dc_dp_out_postsuspend;
}
} else if (def_out->type == TEGRA_DC_OUT_HDMI) {
def_out->hdmi_out = devm_kzalloc(&ndev->dev,
sizeof(struct tegra_hdmi_out), GFP_KERNEL);
if (!def_out->hdmi_out) {
err = -ENOMEM;
goto fail_parse;
}
np_target_disp = pdata->panel_np;
if (!of_property_read_u32(np_target_disp,
"nvidia,hdmi-fpd-bridge", &temp)) {
def_out->hdmi_out->hdmi2fpd_bridge_enable = (bool)temp;
OF_DC_LOG("hdmi2fpd_bridge_enabled %d\n",
def_out->hdmi_out->hdmi2fpd_bridge_enable);
}
if (!of_property_read_u32(np_target_disp,
"nvidia,hdmi-gmsl-bridge", &temp)) {
def_out->hdmi_out->hdmi2gmsl_bridge_enable = (bool)temp;
OF_DC_LOG("hdmi2gmsl_bridge_enabled %d\n",
def_out->hdmi_out->hdmi2gmsl_bridge_enable);
}
if (!of_property_read_u32(np_target_disp,
"nvidia,hdmi-dsi-bridge", &temp)) {
def_out->hdmi_out->
hdmi2dsi_bridge_enable = (bool)temp;
OF_DC_LOG("hdmi2dsi_bridge_enabled %d\n",
def_out->hdmi_out->
hdmi2dsi_bridge_enable);
}
if (!of_property_read_u32(np_target_disp,
"generic-infoframe-type", &temp))
def_out->hdmi_out->
generic_infoframe_type = (u8)temp;
else
def_out->hdmi_out->
generic_infoframe_type =
HDMI_INFOFRAME_TYPE_HDR;
pr_info("generic_infoframe_type: 0x%02x\n",
def_out->hdmi_out->
generic_infoframe_type);
if (def_out->hdmi_out->generic_infoframe_type ==
HDMI_INFOFRAME_TYPE_SPD)
parse_spd_infoframe(ndev, np_target_disp,
def_out);
/* fixed panel ops is dominant. If fixed panel ops
* is not defined, we set default hdmi panel ops */
if (!def_out->enable && !def_out->disable) {
def_out->enable = dc_hdmi_out_enable;
def_out->disable = dc_hdmi_out_disable;
def_out->hotplug_init = dc_hdmi_hotplug_init;
def_out->postsuspend = dc_hdmi_postsuspend;
}
} else if (def_out->type == TEGRA_DC_OUT_LVDS) {
np_target_disp = pdata->panel_np;
} else {
dev_err(&ndev->dev, "failed to identify out type %d\n",
def_out->type);
err = -ENOENT;
goto fail_parse;
}
if (!np_target_disp) {
dev_err(&ndev->dev, "failed to identify target panel\n");
err = -ENODEV;
goto fail_parse;
}
of_property_for_each_u32(np, "nvidia,dc-flags", prop, p, temp) {
if (!is_dc_default_flag(temp)) {
pr_err("invalid dc-flags\n");
goto fail_parse;
}
pdata->flags |= (unsigned long)temp;
}
OF_DC_LOG("dc flag %lu\n", pdata->flags);
err = parse_disp_default_out(ndev, pdata);
if (err) {
dev_err(&ndev->dev, "failed to parse disp_default_out,%d\n",
err);
goto fail_parse;
}
if (pdata->default_out->type == TEGRA_DC_OUT_DSI) {
if (!of_property_read_u32(np_target_disp,
"nvidia,dsi-hdmi-bridge", &temp)) {
pdata->default_out->is_ext_panel = (int)temp;
OF_DC_LOG("is_ext_dp_panel %d\n", temp);
}
}
if ((pdata->default_out->type == TEGRA_DC_OUT_DP) ||
(pdata->default_out->type == TEGRA_DC_OUT_FAKE_DP)) {
if (!of_property_read_u32(np_target_disp,
"nvidia,is_ext_dp_panel", &temp)) {
pdata->default_out->is_ext_panel = (int)temp;
OF_DC_LOG("is_ext_dp_panel %d\n", temp);
}
}
timings_np = of_get_child_by_name(np_target_disp, "display-timings");
if (!timings_np) {
if (def_out->type == TEGRA_DC_OUT_DSI &&
!pdata->default_out->is_ext_panel) {
pr_err("%s: could not find display-timings node\n",
__func__);
goto fail_parse;
}
} else if (def_out->type == TEGRA_DC_OUT_DSI ||
def_out->type == TEGRA_DC_OUT_FAKE_DP ||
def_out->type == TEGRA_DC_OUT_DP ||
def_out->type == TEGRA_DC_OUT_LVDS) {
def_out->n_modes =
of_get_child_count(timings_np);
if (def_out->n_modes == 0) {
/*
* Should never happen !
*/
dev_err(&ndev->dev, "no timing given\n");
goto fail_parse;
}
def_out->modes = devm_kzalloc(&ndev->dev,
def_out->n_modes *
sizeof(struct tegra_dc_mode), GFP_KERNEL);
if (!def_out->modes) {
dev_err(&ndev->dev, "not enough memory\n");
goto fail_parse;
}
} else if (def_out->type == TEGRA_DC_OUT_HDMI) {
def_out->n_modes =
of_get_child_count(timings_np);
if (def_out->n_modes) {
def_out->modes = devm_kzalloc(&ndev->dev,
def_out->n_modes *
sizeof(struct tegra_dc_mode), GFP_KERNEL);
if (!def_out->modes) {
dev_err(&ndev->dev, "not enough memory\n");
goto fail_parse;
}
} else {
if (tegra_fb_is_console_enabled(pdata)) {
/*
* Should never happen !
*/
dev_err(&ndev->dev, "no timing provided\n");
goto fail_parse;
}
}
}
#if defined(CONFIG_FRAMEBUFFER_CONSOLE)
/* Default mode for fbconsole */
if ((pdata->default_out->type == TEGRA_DC_OUT_HDMI) ||
(pdata->default_out->type == TEGRA_DC_OUT_DP)) {
err = parse_fbcon_default_mode(np_target_disp, ndev, pdata);
if (err) {
pr_err("%s: parsing fbcon mode failed\n", __func__);
goto fail_parse;
}
}
#endif
vrr_np = of_get_child_by_name(np_target_disp, "vrr-settings");
if (!vrr_np || (def_out->n_modes < 2)) {
pr_debug("%s: could not find vrr-settings node\n", __func__);
} else if (def_out->type != TEGRA_DC_OUT_DSI) {
dev_err(&ndev->dev,
"vrr-settings specified for a non-DSI head, disregarded\n");
} else {
dma_addr_t dma_addr;
struct tegra_vrr *vrr;
def_out->vrr = dma_alloc_coherent(NULL, PAGE_SIZE,
&dma_addr, GFP_KERNEL);
vrr = def_out->vrr;
if (vrr) {
#if defined(CONFIG_TRUSTED_LITTLE_KERNEL) || defined(CONFIG_TRUSTY)
int retval;
retval = tegra_hdmivrr_te_set_buf(vrr);
if (retval) {
dev_err(&ndev->dev, "failed to set buffer\n");
goto fail_parse;
}
#endif
} else {
dev_err(&ndev->dev, "not enough memory\n");
goto fail_parse;
}
err = parse_vrr_settings(ndev, vrr_np, vrr);
if (err)
goto fail_parse;
}
if (!of_property_read_u32(np_target_disp,
"nvidia,hdmi-vrr-caps", &temp)) {
if (def_out->type != TEGRA_DC_OUT_HDMI) {
dev_err(&ndev->dev,
"nvidia,hdmi-vrr-caps specified for a non-HDMI head, disregarded\n");
} else {
def_out->vrr = devm_kzalloc(&ndev->dev,
sizeof(struct tegra_vrr), GFP_KERNEL);
if (!def_out->vrr) {
dev_err(&ndev->dev, "not enough memory\n");
goto fail_parse;
}
OF_DC_LOG("nvidia,hdmi-vrr-caps: %d\n", temp);
#if defined(CONFIG_TRUSTED_LITTLE_KERNEL) || defined(CONFIG_TRUSTY)
check_val = tegra_hdmivrr_te_set_buf(
def_out->vrr);
if (check_val) {
dev_err(&ndev->dev,
"failed to set buffer\n");
goto fail_parse;
}
#endif
}
} else
pr_debug("%s: nvidia,hdmi-vrr-caps not present\n", __func__);
pdata->default_out->vrr_hotplug_state = TEGRA_HPD_STATE_NORMAL;
if (tegra_dc_is_t21x()) {
cmu_np = of_get_child_by_name(np_target_disp, "cmu");
if (!cmu_np) {
pr_debug("%s: could not find cmu node\n", __func__);
} else {
pdata->cmu = devm_kzalloc(&ndev->dev,
sizeof(struct tegra_dc_cmu), GFP_KERNEL);
if (!pdata->cmu)
goto fail_parse;
}
cmu_adbRGB_np = of_get_child_by_name(np_target_disp,
"cmu_adobe_rgb");
if (!cmu_adbRGB_np) {
pr_debug("%s: could not find cmu node for adobeRGB\n",
__func__);
} else {
pdata->cmu_adbRGB = devm_kzalloc(&ndev->dev,
sizeof(struct tegra_dc_cmu), GFP_KERNEL);
if (!pdata->cmu_adbRGB)
goto fail_parse;
}
if (pdata->cmu != NULL) {
err = parse_cmu_data(cmu_np, pdata->cmu);
if (err)
goto fail_parse;
}
if (pdata->cmu_adbRGB != NULL) {
err = parse_cmu_data(cmu_adbRGB_np, pdata->cmu_adbRGB);
if (err)
goto fail_parse;
}
}
if (tegra_dc_is_nvdisplay()) {
cmu_np = of_get_child_by_name(np_target_disp, "nvdisp-cmu");
if (!cmu_np) {
pr_debug("%s: could not find cmu node\n", __func__);
} else {
pdata->nvdisp_cmu = devm_kzalloc(&ndev->dev,
sizeof(struct tegra_dc_nvdisp_cmu), GFP_KERNEL);
if (!pdata->nvdisp_cmu)
goto fail_parse;
}
if (pdata->nvdisp_cmu != NULL) {
err = parse_nvdisp_cmu_data(cmu_np, pdata->nvdisp_cmu);
if (err)
goto fail_parse;
}
}
if (def_out->modes != NULL) {
struct tegra_dc_mode *cur_mode
= def_out->modes;
for_each_child_of_node(timings_np, entry) {
err = parse_modes(def_out, entry, cur_mode);
if (err)
goto fail_parse;
cur_mode++;
}
}
if (of_property_read_u32(pdata->panel_np, "nvidia,default_color_space",
&pdata->default_clr_space))
pdata->default_clr_space = 0;
if (!pdata_initialized) {
if (!of_property_read_u32(np, "nvidia,fb-win", &temp)) {
pdata->fb->win = (int)temp;
OF_DC_LOG("fb window Index %d\n", pdata->fb->win);
}
if (!of_property_read_u32(np, "win-mask", &temp)) {
pdata->win_mask = (u32)temp;
OF_DC_LOG("win mask 0x%x\n", temp);
}
}
if (!of_property_read_u32(np, "nvidia,emc-clk-rate", &temp)) {
pdata->emc_clk_rate = (unsigned long)temp;
OF_DC_LOG("emc clk rate %lu\n", pdata->emc_clk_rate);
}
if (!of_property_read_u32(np, "nvidia,cmu-enable", &temp)) {
pdata->cmu_enable = (bool)temp;
OF_DC_LOG("cmu enable %d\n", pdata->cmu_enable);
} else {
pdata->cmu_enable = false;
}
dev_info(&ndev->dev, "DT parsed successfully\n");
of_node_put(timings_np);
of_node_put(cmu_np);
of_node_put(cmu_adbRGB_np);
of_node_put(np_target_disp);
return pdata;
fail_parse:
of_node_put(cmu_np);
of_node_put(cmu_adbRGB_np);
if (!boot_pdata && !IS_ERR_OR_NULL(pdata)) {
if (!IS_ERR_OR_NULL(pdata->fb))
devm_kfree(&ndev->dev, pdata->fb);
if (!IS_ERR_OR_NULL(pdata->default_out))
devm_kfree(&ndev->dev, pdata->default_out);
devm_kfree(&ndev->dev, pdata);
}
return ERR_PTR(err);
}
#ifdef CONFIG_OF
struct tegra_dc_common_platform_data
*of_dc_common_parse_platform_data(struct platform_device *pdev)
{
struct tegra_dc_common_platform_data *pdata;
struct device_node *np = pdev->dev.of_node;
struct device_node *imp_np = NULL;
u32 temp;
pdata = devm_kzalloc(&pdev->dev,
sizeof(struct tegra_dc_common_platform_data), GFP_KERNEL);
if (!pdata) {
dev_err(&pdev->dev, "not enough memory\n");
return NULL;
}
if (!of_property_read_u32(np, "nvidia,valid_heads", &temp)) {
pdata->valid_heads = (int)temp;
OF_DC_LOG("valid_heads %d\n", pdata->valid_heads);
} else {
goto fail_parse_pdata;
}
imp_np = of_parse_phandle(np, "nvidia,disp_imp_table", 0);
if (imp_np && of_device_is_available(imp_np)) {
pdata->imp_table = devm_kzalloc(&pdev->dev,
sizeof(*(pdata->imp_table)), GFP_KERNEL);
if (!pdata->imp_table)
goto fail_parse_pdata;
if (tegra_dc_parse_imp_data(imp_np, pdev, pdata->imp_table))
goto fail_parse_imp_table;
}
return pdata;
fail_parse_imp_table:
kfree(pdata->imp_table);
fail_parse_pdata:
kfree(pdata);
return NULL;
}
#else
struct tegra_dc_common_platform_data
*of_dc_common_parse_platform_data(struct platform_device *pdev)
{
return NULL;
}
#endif
static int __init check_fb_console_map_default(void)
{
struct device_node *np_l4t = NULL;
struct property *pp_l4t = NULL;
int len, res = 0;
np_l4t = of_find_node_by_path("/chosen/plugin-manager/odm-data");
if (np_l4t) {
pp_l4t = of_find_property(np_l4t, "l4t", &len);
if (pp_l4t) {
os_l4t = true;
res = 1;
}
pr_info("OS set in device tree is%s L4T.\n", pp_l4t ? "":" not");
}
return res;
}
core_initcall(check_fb_console_map_default);
bool is_os_l4t(void)
{
return os_l4t;
}