mirror of
https://github.com/NVIDIA/open-gpu-kernel-modules.git
synced 2026-01-27 03:29:47 +00:00
1015 lines
32 KiB
C
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
|
|
}
|