Files
open-gpu-kernel-modules/kernel-open/nvidia/nv-dsi-parse-panel-props.c
Maneet Singh 307159f262 580.65.06
2025-08-04 11:15:02 -07:00

1015 lines
32 KiB
C

/*
* SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#define __NO_VERSION__
#include "os-interface.h"
#include "nv-linux.h"
#include "os_dsi_panel_props.h"
int bl_name_len;
static u32 *dsi_read_prop_array
(
const struct device_node *np,
struct property *prop,
u32 *array_size
)
{
#if NV_SUPPORTS_PLATFORM_DEVICE
u32 *val_array = NULL;
u32 count = 0;
int ret = 0;
if (!prop)
return NULL;
count = of_property_count_elems_of_size(np, prop->name, sizeof(u32));
if (count > 0)
{
NV_KMALLOC(val_array, sizeof(u32) * count);
if (val_array == NULL)
{
nv_printf(NV_DBG_ERRORS, "NVRM: dsi_read_prop_array, failed to allocate memory for values of DSI property %s", prop->name);
return ERR_PTR(-ENOMEM);
}
}
else
{
nv_printf(NV_DBG_ERRORS, "NVRM: dsi_read_prop_array, failed to get elements count in property %s\n", prop->name);
return ERR_PTR(-ENOSYS);
}
ret = of_property_read_variable_u32_array(np, prop->name,
val_array, 0, count);
if (IS_ERR(&ret))
{
nv_printf(NV_DBG_ERRORS, "NVRM: dsi_read_prop_array, failed to read property %s", prop->name);
NV_KFREE(val_array, sizeof(u32) * count);
val_array = NULL;
return ERR_PTR(ret);
}
*array_size = count;
return val_array;
#else
nv_printf(NV_DBG_ERRORS, "NVRM: dsi_read_prop_array, platform device not supported\n");
return ERR_PTR(-ENOSYS);
#endif
}
static int dsi_get_panel_timings(struct device_node *np_panel, DSI_PANEL_INFO *panelInfo)
{
#if NV_SUPPORTS_PLATFORM_DEVICE
struct device_node *np = NULL;
NvU32 temp;
DSITIMINGS *modes = &panelInfo->dsiTimings;
// Get Panel Node from active-panel phandle
np = of_parse_phandle(np_panel, "nvidia,panel-timings", 0);
if (!np) {
nv_printf(NV_DBG_ERRORS, "NVRM: could not find panel timings node for DSI Panel\n");
return -ENOENT;
}
if (!of_property_read_u32(np, "clock-frequency", &temp)) {
modes->pixelClkRate = temp;
} else {
goto parse_mode_timings_fail;
}
if (!of_property_read_u32(np, "hsync-len", &temp)) {
modes->hSyncWidth = temp;
} else {
goto parse_mode_timings_fail;
}
if (!of_property_read_u32(np, "vsync-len", &temp)) {
modes->vSyncWidth = temp;
} else {
goto parse_mode_timings_fail;
}
if (!of_property_read_u32(np, "hback-porch", &temp)) {
modes->hBackPorch = temp;
} else {
goto parse_mode_timings_fail;
}
if (!of_property_read_u32(np, "vback-porch", &temp)) {
modes->vBackPorch = temp;
} else {
goto parse_mode_timings_fail;
}
if (!of_property_read_u32(np, "hactive", &temp)) {
modes->hActive = temp;
} else {
goto parse_mode_timings_fail;
}
if (!of_property_read_u32(np, "vactive", &temp)) {
modes->vActive = temp;
} else {
goto parse_mode_timings_fail;
}
if (!of_property_read_u32(np, "hfront-porch", &temp)) {
modes->hFrontPorch = temp;
} else {
goto parse_mode_timings_fail;
}
if (!of_property_read_u32(np, "vfront-porch", &temp)) {
modes->vFrontPorch = temp;
} else {
goto parse_mode_timings_fail;
}
of_node_put(np);
return 0U;
parse_mode_timings_fail:
nv_printf(NV_DBG_ERRORS, "NVRM: One of the mode timings is missing in DSI Panel mode-timings!\n");
of_node_put(np);
#endif
return -ENOENT;
}
static int dsi_get_panel_gpio(struct device_node *node, DSI_PANEL_INFO *panel)
{
char *label = NULL;
int count;
(void)label;
(void)count;
// If gpios are already populated, just return
if (panel->panel_gpio_populated)
return 0;
if (!node) {
nv_printf(NV_DBG_ERRORS, "NVRM: DSI Panel node not available\n");
return -ENOENT;
}
#if NV_SUPPORTS_PLATFORM_DEVICE
panel->panel_gpio[DSI_GPIO_LCD_RESET] =
of_get_named_gpio(node, "nvidia,panel-rst-gpio", 0);
panel->panel_gpio[DSI_GPIO_PANEL_EN] =
of_get_named_gpio(node, "nvidia,panel-en-gpio", 0);
panel->panel_gpio[DSI_GPIO_PANEL_EN_1] =
of_get_named_gpio(node, "nvidia,panel-en-1-gpio", 0);
panel->panel_gpio[DSI_GPIO_BL_ENABLE] =
of_get_named_gpio(node, "nvidia,panel-bl-en-gpio", 0);
panel->panel_gpio[DSI_GPIO_BL_PWM] =
of_get_named_gpio(node, "nvidia,panel-bl-pwm-gpio", 0);
panel->panel_gpio[DSI_GPIO_TE] =
of_get_named_gpio(node, "nvidia,te-gpio", 0);
panel->panel_gpio[DSI_GPIO_AVDD_AVEE_EN] =
of_get_named_gpio(node, "nvidia,avdd-avee-en-gpio", 0);
panel->panel_gpio[DSI_GPIO_VDD_1V8_LCD_EN] =
of_get_named_gpio(node, "nvidia,vdd-1v8-lcd-en-gpio", 0);
panel->panel_gpio[DSI_GPIO_BRIDGE_EN_0] =
of_get_named_gpio(node, "nvidia,panel-bridge-en-0-gpio", 0);
panel->panel_gpio[DSI_GPIO_BRIDGE_EN_1] =
of_get_named_gpio(node, "nvidia,panel-bridge-en-1-gpio", 0);
panel->panel_gpio[DSI_GPIO_BRIDGE_REFCLK_EN] =
of_get_named_gpio(node, "nvidia,panel-bridge-refclk-en-gpio", 0);
for (count = 0; count < DSI_N_GPIO_PANEL; count++) {
if (gpio_is_valid(panel->panel_gpio[count])) {
switch (count) {
case DSI_GPIO_LCD_RESET:
label = "dsi-panel-reset";
break;
case DSI_GPIO_PANEL_EN:
label = "dsi-panel-en";
break;
case DSI_GPIO_PANEL_EN_1:
label = "dsi-panel-en-1";
break;
case DSI_GPIO_BL_ENABLE:
label = "dsi-panel-bl-enable";
break;
case DSI_GPIO_BL_PWM:
label = "dsi-panel-pwm";
break;
case DSI_GPIO_TE:
if (panel->dsiEnVRR != NV_TRUE) {
panel->panel_gpio[count] = -1;
} else {
label = "dsi-panel-te";
panel->dsiVrrPanelSupportsTe = NV_TRUE;
}
break;
case DSI_GPIO_AVDD_AVEE_EN:
label = "dsi-panel-avdd-avee-en";
break;
case DSI_GPIO_VDD_1V8_LCD_EN:
label = "dsi-panel-vdd-1v8-lcd-en";
break;
case DSI_GPIO_BRIDGE_EN_0:
label = "dsi-panel-bridge-en-0";
break;
case DSI_GPIO_BRIDGE_EN_1:
label = "dsi-panel-bridge-en-1";
break;
case DSI_GPIO_BRIDGE_REFCLK_EN:
label = "dsi-panel-bridge-refclk-en";
break;
default:
nv_printf(NV_DBG_INFO, "NVRM: DSI Panel invalid gpio entry at index %d\n", count);
}
if (label) {
gpio_request(panel->panel_gpio[count], label);
label = NULL;
}
}
}
panel->panel_gpio_populated = true;
return 0U;
#else
return -EINVAL;
#endif
}
static int dsi_parse_pps_data
(
const struct device_node *node,
struct property *prop,
NvU32 *pps
)
{
__be32 *prop_val_ptr;
u32 count = 0;
if (!prop)
return -ENOENT;
prop_val_ptr = prop->value;
#define PPS_COUNT 32
for (count = 0; count < PPS_COUNT; count++) {
pps[count] = be32_to_cpu(*prop_val_ptr++);
}
#undef PPS_COUNT
return 0U;
}
static int parse_dsi_properties(const struct device_node *np_dsi, DSI_PANEL_INFO *dsi)
{
#if NV_SUPPORTS_PLATFORM_DEVICE
u32 temp;
int ret = 0;
#if defined(NV_OF_PROPERTY_FOR_EACH_U32_HAS_INTERNAL_ARGS)
const __be32 *p;
struct property *prop;
#endif
struct device_node *np_dsi_panel;
// Get Panel Node from active-panel phandle
np_dsi_panel = of_parse_phandle(np_dsi, "nvidia,active-panel", 0);
if (np_dsi_panel == NULL)
{
nv_printf(NV_DBG_ERRORS, "NVRM: None of the dsi panel nodes enabled in DT!\n");
return -EINVAL;
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,enable-hs-clk-in-lp-mode", &temp))
dsi->enable_hs_clock_on_lp_cmd_mode = (u8)temp;
if (of_property_read_bool(np_dsi_panel,
"nvidia,set-max-dsi-timeout"))
dsi->set_max_timeout = true;
if (of_property_read_bool(np_dsi_panel,
"nvidia,use-legacy-dphy-core"))
dsi->use_legacy_dphy_core = true;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-refresh-rate-adj", &temp))
dsi->refresh_rate_adj = (u8)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-n-data-lanes", &temp))
dsi->n_data_lanes = (u8)temp;
if (of_property_read_bool(np_dsi_panel,
"nvidia,swap-data-lane-polarity"))
dsi->swap_data_lane_polarity = true;
if (of_property_read_bool(np_dsi_panel,
"nvidia,swap-clock-lane-polarity"))
dsi->swap_clock_lane_polarity = true;
if (of_property_read_bool(np_dsi_panel,
"nvidia,reverse-clock-polarity"))
dsi->reverse_clock_polarity = true;
if (!of_property_read_u32_array(np_dsi_panel,
"nvidia,lane-xbar-ctrl",
dsi->lane_xbar_ctrl, dsi->n_data_lanes))
dsi->lane_xbar_exists = true;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-type", &temp))
{
dsi->dsiPhyType = (u8)temp;
if ((temp != DSI_DPHY) &&
(temp != DSI_CPHY))
{
nv_printf(NV_DBG_ERRORS,"NVRM: invalid dsi phy type 0x%x\n", temp);
ret = -EINVAL;
goto parse_dsi_settings_fail;
}
}
if (of_property_read_bool(np_dsi_panel,
"nvidia,cphy-data-scrambling"))
dsi->en_data_scrambling = true;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-video-burst-mode", &temp))
{
dsi->video_burst_mode = (u8)temp;
if ((temp != DSI_VIDEO_NON_BURST_MODE) &&
(temp != DSI_VIDEO_NON_BURST_MODE_WITH_SYNC_END) &&
(temp != DSI_VIDEO_BURST_MODE_LOWEST_SPEED) &&
(temp != DSI_VIDEO_BURST_MODE_LOW_SPEED) &&
(temp != DSI_VIDEO_BURST_MODE_MEDIUM_SPEED) &&
(temp != DSI_VIDEO_BURST_MODE_FAST_SPEED) &&
(temp != DSI_VIDEO_BURST_MODE_FASTEST_SPEED))
{
nv_printf(NV_DBG_ERRORS,"NVRM: 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 != DSI_PIXEL_FORMAT_16BIT_P) &&
(temp != DSI_PIXEL_FORMAT_18BIT_P) &&
(temp != DSI_PIXEL_FORMAT_18BIT_NP) &&
(temp != DSI_PIXEL_FORMAT_24BIT_P) &&
(temp != DSI_PIXEL_FORMAT_30BIT_P) &&
(temp != DSI_PIXEL_FORMAT_36BIT_P) &&
(temp != DSI_PIXEL_FORMAT_8BIT_DSC) &&
(temp != DSI_PIXEL_FORMAT_10BIT_DSC) &&
(temp != DSI_PIXEL_FORMAT_12BIT_DSC) &&
(temp != DSI_PIXEL_FORMAT_16BIT_DSC))
{
nv_printf(NV_DBG_ERRORS,"NVRM: 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;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-rated-refresh-rate", &temp))
dsi->rated_refresh_rate = (u8)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-virtual-channel", &temp))
{
dsi->virtual_channel = (u8)temp;
if ((temp != DSI_VIRTUAL_CHANNEL_0) &&
(temp != DSI_VIRTUAL_CHANNEL_1) &&
(temp != DSI_VIRTUAL_CHANNEL_2) &&
(temp != DSI_VIRTUAL_CHANNEL_3))
{
nv_printf(NV_DBG_ERRORS,"NVRM: invalid dsi virtual channel\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 (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-panel-reset", &temp))
dsi->panel_reset = (u8)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-te-polarity-low", &temp))
dsi->te_polarity_low = (u8)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-lp00-pre-panel-wakeup", &temp))
dsi->lp00_pre_panel_wakeup = (u8)temp;
if (of_find_property(np_dsi_panel,
"nvidia,dsi-bl-name", &bl_name_len))
{
NV_KMALLOC(dsi->bl_name, sizeof(u8) * bl_name_len);
if (!of_property_read_string(np_dsi_panel,
"nvidia,dsi-bl-name",
(const char **)&dsi->bl_name)) {
} else {
nv_printf(NV_DBG_ERRORS, "NVRM: dsi error parsing bl name\n");
NV_KFREE(dsi->bl_name, sizeof(u8) * bl_name_len);
}
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-ganged-type", &temp)) {
dsi->ganged_type = (u8)temp;
/* Set pixel width to 1 by default for even-odd split */
if (dsi->ganged_type == 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;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-ganged-overlap", &temp)) {
dsi->ganged_overlap = (u16)temp;
if (!dsi->ganged_type)
nv_printf(NV_DBG_ERRORS, "NVRM: 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;
if (!dsi->ganged_type)
nv_printf(NV_DBG_ERRORS, "NVRM: 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;
if (!dsi->ganged_type)
nv_printf(NV_DBG_ERRORS, "NVRM: 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;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-suspend-aggr", &temp))
dsi->suspend_aggr = (u8)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-edp-bridge", &temp))
dsi->dsi2edp_bridge_enable = (bool)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-lvds-bridge", &temp))
dsi->dsi2lvds_bridge_enable = (bool)temp;
#if defined(NV_OF_PROPERTY_FOR_EACH_U32_HAS_INTERNAL_ARGS)
of_property_for_each_u32(np_dsi_panel, "nvidia,dsi-dpd-pads", prop, p, temp)
#else
of_property_for_each_u32(np_dsi_panel, "nvidia,dsi-dpd-pads", temp)
#endif
dsi->dpd_dsi_pads |= (u32)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-power-saving-suspend", &temp))
dsi->power_saving_suspend = (bool)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-ulpm-not-support", &temp))
dsi->ulpm_not_supported = (bool)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-video-data-type", &temp)) {
dsi->video_data_type = (u8)temp;
if ((temp != DSI_VIDEO_TYPE_VIDEO_MODE) &&
(temp != DSI_VIDEO_TYPE_COMMAND_MODE))
{
nv_printf(NV_DBG_ERRORS, "NVRM: 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 != DSI_VIDEO_CLOCK_CONTINUOUS) &&
(temp != DSI_VIDEO_CLOCK_TX_ONLY))
{
nv_printf(NV_DBG_ERRORS, "NVRM: invalid dsi video clk mode\n");
ret = -EINVAL;
goto parse_dsi_settings_fail;
}
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,enable-vrr", &temp))
dsi->dsiEnVRR = (u8)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,vrr-force-set-te-pin", &temp))
dsi->dsiForceSetTePin = (u8)temp;
if (of_property_read_bool(np_dsi_panel,
"nvidia,send-init-cmds-early"))
dsi->sendInitCmdsEarly = true;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-n-init-cmd", &temp)) {
dsi->n_init_cmd = (u16)temp;
}
if (dsi->n_init_cmd > 0) {
dsi->dsi_init_cmd_array = dsi_read_prop_array(np_dsi_panel,
of_find_property(np_dsi_panel, "nvidia,dsi-init-cmd", NULL),
&dsi->init_cmd_array_size);
}
if (dsi->n_init_cmd &&
IS_ERR_OR_NULL(dsi->dsi_init_cmd_array)) {
nv_printf(NV_DBG_ERRORS, "NVRM: DSI init cmd parsing 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;
}
if (dsi->n_postvideo_cmd > 0) {
dsi->dsi_postvideo_cmd_array = dsi_read_prop_array(np_dsi_panel,
of_find_property(np_dsi_panel, "nvidia,dsi-postvideo-cmd", NULL),
&dsi->postvideo_cmd_array_size);
}
if (dsi->n_postvideo_cmd &&
IS_ERR_OR_NULL(dsi->dsi_postvideo_cmd_array)) {
nv_printf(NV_DBG_ERRORS, "NVRM: DSI postvideo cmd parsing 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;
}
if (dsi->n_suspend_cmd > 0) {
dsi->dsi_suspend_cmd_array = dsi_read_prop_array(np_dsi_panel,
of_find_property(np_dsi_panel, "nvidia,dsi-suspend-cmd", NULL),
&dsi->suspend_cmd_array_size);
}
if (dsi->n_suspend_cmd &&
IS_ERR_OR_NULL(dsi->dsi_suspend_cmd_array)) {
nv_printf(NV_DBG_ERRORS, "NVRM: DSI suspend cmd parsing 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;
}
if (dsi->n_early_suspend_cmd > 0) {
dsi->dsi_early_suspend_cmd_array = dsi_read_prop_array(np_dsi_panel,
of_find_property(np_dsi_panel, "nvidia,dsi-early-suspend-cmd", NULL),
&dsi->early_suspend_cmd_array_size);
}
if (dsi->n_early_suspend_cmd &&
IS_ERR_OR_NULL(dsi->dsi_early_suspend_cmd_array)) {
nv_printf(NV_DBG_ERRORS, "NVRM: DSI early suspend cmd parsing 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;
}
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-n-late-resume-cmd", &temp)) {
dsi->n_late_resume_cmd = (u16)temp;
}
if (dsi->n_late_resume_cmd > 0) {
dsi->dsi_late_resume_cmd_array = dsi_read_prop_array(np_dsi_panel,
of_find_property(np_dsi_panel, "nvidia,dsi-late-resume-cmd", NULL),
&dsi->late_resume_cmd_array_size);
}
if (dsi->n_late_resume_cmd &&
IS_ERR_OR_NULL(dsi->dsi_late_resume_cmd_array)) {
nv_printf(NV_DBG_ERRORS, "NVRM: DSI late resume cmd parsing from DT failed\n");
ret = -EINVAL;
goto parse_dsi_settings_fail;
};
dsi->pktSeq_array = dsi_read_prop_array(np_dsi_panel,
of_find_property(np_dsi_panel, "nvidia,dsi-pkt-seq", NULL),
&dsi->pktSeq_array_size);
if (IS_ERR(dsi->pktSeq_array)) {
nv_printf(NV_DBG_ERRORS, "NVRM: DSI packet seq parsing 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->phyTimingNs.t_hsdexit_ns = (u16)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-hstrail", &temp))
dsi->phyTimingNs.t_hstrail_ns = (u16)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-datzero", &temp))
dsi->phyTimingNs.t_datzero_ns = (u16)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-hsprepare", &temp))
dsi->phyTimingNs.t_hsprepare_ns = (u16)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-hsprebegin", &temp))
dsi->phyTimingNs.t_hsprebegin_ns = (u16)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-hspost", &temp))
dsi->phyTimingNs.t_hspost_ns = (u16)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-clktrail", &temp))
dsi->phyTimingNs.t_clktrail_ns = (u16)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-clkpost", &temp))
dsi->phyTimingNs.t_clkpost_ns = (u16)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-clkzero", &temp))
dsi->phyTimingNs.t_clkzero_ns = (u16)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-tlpx", &temp))
dsi->phyTimingNs.t_tlpx_ns = (u16)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-clkprepare", &temp))
dsi->phyTimingNs.t_clkprepare_ns = (u16)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-clkpre", &temp))
dsi->phyTimingNs.t_clkpre_ns = (u16)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-wakeup", &temp))
dsi->phyTimingNs.t_wakeup_ns = (u16)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-taget", &temp))
dsi->phyTimingNs.t_taget_ns = (u16)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-tasure", &temp))
dsi->phyTimingNs.t_tasure_ns = (u16)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsi-phy-tago", &temp))
dsi->phyTimingNs.t_tago_ns = (u16)temp;
if (of_property_read_bool(np_dsi_panel,
"nvidia,enable-link-compression"))
dsi->dsiDscEnable = true;
if (of_property_read_bool(np_dsi_panel,
"nvidia,enable-dual-dsc"))
dsi->dsiDscEnDualDsc = true;
if (of_property_read_bool(np_dsi_panel,
"nvidia,enable-block-pred"))
dsi->dsiDscEnBlockPrediction = true;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,slice-height", &temp))
dsi->dsiDscSliceHeight = (u32)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,num-of-slices", &temp))
dsi->dsiDscNumSlices = (u32)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,comp-rate", &temp))
dsi->dsiDscBpp = (u32)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,version-major", &temp))
dsi->dsiDscDecoderMajorVersion = (u32)temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,version-minor", &temp))
dsi->dsiDscDecoderMinorVersion = (u32)temp;
if (of_property_read_bool(np_dsi_panel,
"nvidia,use-custom-pps")) {
dsi->dsiDscUseCustomPPS = true;
ret = dsi_parse_pps_data(np_dsi_panel,
of_find_property(np_dsi_panel,
"nvidia,custom-pps-data", NULL),
dsi->dsiDscCustomPPSData);
if (ret != NV_OK) {
nv_printf(NV_DBG_ERRORS, "NVRM: Parsing DSI Panel Custom PPS data failed\n");
goto parse_dsi_settings_fail;
}
}
if (of_property_read_bool(np_dsi, "nvidia,dsi-csi-loopback"))
dsi->dsi_csi_loopback = 1;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,vpll0-rate-hz", &temp))
dsi->vpll0_rate_hz = temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsipll-vco-rate-hz", &temp))
dsi->dsipll_vco_rate_hz = temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsipll-clkouta-rate-hz", &temp))
dsi->dsipll_clkouta_rate_hz = temp;
if (!of_property_read_u32(np_dsi_panel,
"nvidia,dsipll-clkoutpn-rate-hz", &temp))
dsi->dsipll_clkoutpn_rate_hz = temp;
ret = dsi_get_panel_timings(np_dsi_panel, dsi);
if (ret != NV_OK) {
nv_printf(NV_DBG_ERRORS, "NVRM: Parsing DSI Panel Timings failed\n");
goto parse_dsi_settings_fail;
}
ret = dsi_get_panel_gpio(np_dsi_panel, dsi);
if (ret != NV_OK) {
nv_printf(NV_DBG_ERRORS, "NVRM: Parsing DSI Panel GPIOs failed\n");
goto parse_dsi_settings_fail;
}
parse_dsi_settings_fail:
return ret;
#else
return -1;
#endif
}
NvBool
nv_dsi_is_panel_connected
(
nv_state_t *nv
)
{
nv_linux_state_t *nvl = NV_GET_NVL_FROM_NV_STATE(nv);
struct device_node *np_dsi = NULL;
struct device_node *np_dsi_panel = NULL;
NvBool ret = NV_TRUE;
np_dsi = of_get_child_by_name(nvl->dev->of_node, "dsi");
if (np_dsi && !of_device_is_available(np_dsi)) {
ret = NV_FALSE;
goto fail;
}
np_dsi_panel = of_parse_phandle(np_dsi, "nvidia,active-panel", 0);
if (np_dsi_panel == NULL)
{
ret = NV_FALSE;
}
fail:
of_node_put(np_dsi_panel);
of_node_put(np_dsi);
return ret;
}
NV_STATUS
nv_dsi_parse_panel_props
(
nv_state_t *nv,
void *dsiPanelInfo
)
{
int ret = NV_OK;
struct device_node *np_dsi = NULL;
nv_linux_state_t *nvl = NV_GET_NVL_FROM_NV_STATE(nv);
np_dsi = of_get_child_by_name(nvl->dev->of_node, "dsi");
if (np_dsi && !of_device_is_available(np_dsi)) {
nv_printf(NV_DBG_ERRORS, "NVRM: dsi node not enabled in DT\n");
of_node_put(np_dsi);
return NV_ERR_NOT_SUPPORTED;
}
ret = parse_dsi_properties(np_dsi, (DSI_PANEL_INFO *)dsiPanelInfo);
return ret;
}
NV_STATUS
nv_dsi_panel_enable
(
nv_state_t *nv,
void *dsiPanelInfo
)
{
#if NV_SUPPORTS_PLATFORM_DEVICE
int ret = NV_OK;
DSI_PANEL_INFO *panelInfo = dsiPanelInfo;
if (gpio_is_valid(panelInfo->panel_gpio[DSI_GPIO_VDD_1V8_LCD_EN])) {
gpio_direction_output(panelInfo->panel_gpio[DSI_GPIO_VDD_1V8_LCD_EN], 1);
}
mdelay(10); //Required 1ms delay
if (gpio_is_valid(panelInfo->panel_gpio[DSI_GPIO_AVDD_AVEE_EN])) {
gpio_direction_output(panelInfo->panel_gpio[DSI_GPIO_AVDD_AVEE_EN], 1);
}
mdelay(20); //Required 10ms delay
// If backlight enable gpio is specified, set it to output direction and pull high
if (gpio_is_valid(panelInfo->panel_gpio[DSI_GPIO_BL_ENABLE])) {
gpio_direction_output(panelInfo->panel_gpio[DSI_GPIO_BL_ENABLE], 1);
}
mdelay(10);
if (gpio_is_valid(panelInfo->panel_gpio[DSI_GPIO_PANEL_EN])) {
gpio_direction_output(panelInfo->panel_gpio[DSI_GPIO_PANEL_EN], 1);
}
mdelay(20); // Requied 10ms
return ret;
#else
return NV_ERR_NOT_SUPPORTED;
#endif
}
NV_STATUS
nv_dsi_panel_reset
(
nv_state_t *nv,
void *dsiPanelInfo
)
{
#if NV_SUPPORTS_PLATFORM_DEVICE
int ret = NV_OK;
int en_panel_rst = -1;
DSI_PANEL_INFO *panelInfo = dsiPanelInfo;
// Assert and deassert Panel reset GPIO
if (gpio_is_valid(panelInfo->panel_gpio[DSI_GPIO_LCD_RESET])) {
en_panel_rst = panelInfo->panel_gpio[DSI_GPIO_LCD_RESET];
} else {
nv_printf(NV_DBG_ERRORS, "DSI Panel reset gpio invalid\n");
goto fail;
}
ret = gpio_direction_output(en_panel_rst, 1);
if (ret < 0) {
nv_printf(NV_DBG_ERRORS, "Deasserting DSI panel reset gpio failed\n");
goto fail;
}
mdelay(10);
ret = gpio_direction_output(en_panel_rst, 0);
if (ret < 0) {
nv_printf(NV_DBG_ERRORS, "Asserting DSI panel reset gpio failed\n");
goto fail;
}
mdelay(10);
ret = gpio_direction_output(en_panel_rst, 1);
if (ret < 0) {
nv_printf(NV_DBG_ERRORS, "Deasserting Dsi panel reset gpio after asserting failed\n");
goto fail;
}
fail:
return ret;
#else
return NV_ERR_NOT_SUPPORTED;
#endif
}
void nv_dsi_panel_disable
(
nv_state_t *nv,
void *dsiPanelInfo
)
{
#if NV_SUPPORTS_PLATFORM_DEVICE
DSI_PANEL_INFO *panelInfo = dsiPanelInfo;
if (gpio_is_valid(panelInfo->panel_gpio[DSI_GPIO_BL_ENABLE])) {
gpio_direction_output(panelInfo->panel_gpio[DSI_GPIO_BL_ENABLE], 0);
}
mdelay(10);
if (gpio_is_valid(panelInfo->panel_gpio[DSI_GPIO_PANEL_EN])) {
gpio_direction_output(panelInfo->panel_gpio[DSI_GPIO_PANEL_EN], 0);
}
// Assert Panel reset GPIO
if (gpio_is_valid(panelInfo->panel_gpio[DSI_GPIO_LCD_RESET])) {
gpio_direction_output(panelInfo->panel_gpio[DSI_GPIO_LCD_RESET], 0);
}
mdelay(20);
if (gpio_is_valid(panelInfo->panel_gpio[DSI_GPIO_AVDD_AVEE_EN])) {
gpio_direction_output(panelInfo->panel_gpio[DSI_GPIO_AVDD_AVEE_EN], 0);
}
mdelay(10);
if (gpio_is_valid(panelInfo->panel_gpio[DSI_GPIO_VDD_1V8_LCD_EN])) {
gpio_direction_output(panelInfo->panel_gpio[DSI_GPIO_VDD_1V8_LCD_EN], 0);
}
#endif
}
void nv_dsi_panel_cleanup
(
nv_state_t *nv,
void *dsiPanelInfo
)
{
#if NV_SUPPORTS_PLATFORM_DEVICE
int count;
DSI_PANEL_INFO *panelInfo = dsiPanelInfo;
if (!IS_ERR_OR_NULL(panelInfo->dsi_init_cmd_array))
NV_KFREE(panelInfo->dsi_init_cmd_array, sizeof(u32) * panelInfo->init_cmd_array_size);
if (!IS_ERR_OR_NULL(panelInfo->dsi_early_suspend_cmd_array))
NV_KFREE(panelInfo->dsi_early_suspend_cmd_array, sizeof(u32) * panelInfo->early_suspend_cmd_array_size);
if (!IS_ERR_OR_NULL(panelInfo->dsi_late_resume_cmd_array))
NV_KFREE(panelInfo->dsi_late_resume_cmd_array, sizeof(u32) * panelInfo->late_resume_cmd_array_size);
if (!IS_ERR_OR_NULL(panelInfo->dsi_postvideo_cmd_array))
NV_KFREE(panelInfo->dsi_postvideo_cmd_array, sizeof(u32) * panelInfo->postvideo_cmd_array_size);
if (!IS_ERR_OR_NULL(panelInfo->dsi_suspend_cmd_array))
NV_KFREE(panelInfo->dsi_suspend_cmd_array, sizeof(u32) * panelInfo->suspend_cmd_array_size);
if (!IS_ERR_OR_NULL(panelInfo->pktSeq_array))
NV_KFREE(panelInfo->pktSeq_array, sizeof(u32) * panelInfo->pktSeq_array_size);
if (panelInfo->bl_name != NULL) {
NV_KFREE(panelInfo->bl_name, sizeof(u8) * bl_name_len);
}
for (count = 0; count < DSI_N_GPIO_PANEL; count++) {
if (gpio_is_valid(panelInfo->panel_gpio[count])) {
gpio_free(panelInfo->panel_gpio[count]);
}
}
panelInfo->panel_gpio_populated = false;
#endif
}