diff --git a/src/mainboard/google/nyan/Kconfig b/src/mainboard/google/nyan/Kconfig index 99a39e08be..4b80ed29e3 100644 --- a/src/mainboard/google/nyan/Kconfig +++ b/src/mainboard/google/nyan/Kconfig @@ -27,6 +27,8 @@ config BOARD_SPECIFIC_OPTIONS # dummy select EC_GOOGLE_CHROMEEC_SPI select SOC_NVIDIA_TEGRA124 select MAINBOARD_HAS_BOOTBLOCK_INIT + select MAINBOARD_DO_NATIVE_VGA_INIT + config MAINBOARD_DIR string diff --git a/src/soc/nvidia/tegra/dc.h b/src/soc/nvidia/tegra/dc.h index 33dbe53ff1..dac2065f5b 100644 --- a/src/soc/nvidia/tegra/dc.h +++ b/src/soc/nvidia/tegra/dc.h @@ -561,4 +561,5 @@ struct disp_ctl_win { }; void display_startup(device_t dev); +void dp_bringup(u32 winb_addr); #endif /* __SOC_NVIDIA_TEGRA_DC_H */ diff --git a/src/soc/nvidia/tegra/displayport.h b/src/soc/nvidia/tegra/displayport.h new file mode 100644 index 0000000000..8a57170bf9 --- /dev/null +++ b/src/soc/nvidia/tegra/displayport.h @@ -0,0 +1,316 @@ +/* + * drivers/video/tegra/dc/dpaux_regs.h + * + * Copyright (c) 2011, NVIDIA Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __SOC_NVIDIA_TEGRA_DISPLAYPORT_H__ +#define __SOC_NVIDIA_TEGRA_DISPLAYPORT_H__ + +/* things we can't get rid of just yet. */ +#define DPAUX_INTR_EN_AUX (0x1) +#define DPAUX_INTR_AUX (0x5) +#define DPAUX_DP_AUXDATA_WRITE_W(i) (0x9 + 4*(i)) +#define DPAUX_DP_AUXDATA_READ_W(i) (0x19 + 4*(i)) +#define DPAUX_DP_AUXADDR (0x29) +#define DPAUX_DP_AUXCTL (0x2d) +#define DPAUX_DP_AUXCTL_CMDLEN_SHIFT (0) +#define DPAUX_DP_AUXCTL_CMDLEN_FIELD (0xff) +#define DPAUX_DP_AUXCTL_CMD_SHIFT (12) +#define DPAUX_DP_AUXCTL_CMD_MASK (0xf << 12) +#define DPAUX_DP_AUXCTL_CMD_I2CWR (0 << 12) +#define DPAUX_DP_AUXCTL_CMD_I2CRD (1 << 12) +#define DPAUX_DP_AUXCTL_CMD_I2CREQWSTAT (2 << 12) +#define DPAUX_DP_AUXCTL_CMD_MOTWR (4 << 12) +#define DPAUX_DP_AUXCTL_CMD_MOTRD (5 << 12) +#define DPAUX_DP_AUXCTL_CMD_MOTREQWSTAT (6 << 12) +#define DPAUX_DP_AUXCTL_CMD_AUXWR (8 << 12) +#define DPAUX_DP_AUXCTL_CMD_AUXRD (9 << 12) +#define DPAUX_DP_AUXCTL_TRANSACTREQ_SHIFT (16) +#define DPAUX_DP_AUXCTL_TRANSACTREQ_MASK (0x1 << 16) +#define DPAUX_DP_AUXCTL_TRANSACTREQ_DONE (0 << 16) +#define DPAUX_DP_AUXCTL_TRANSACTREQ_PENDING (1 << 16) +#define DPAUX_DP_AUXCTL_RST_SHIFT (31) +#define DPAUX_DP_AUXCTL_RST_DEASSERT (0 << 31) +#define DPAUX_DP_AUXCTL_RST_ASSERT (1 << 31) +#define DPAUX_DP_AUXSTAT (0x31) +#define DPAUX_DP_AUXSTAT_HPD_STATUS_SHIFT (28) +#define DPAUX_DP_AUXSTAT_HPD_STATUS_UNPLUG (0 << 28) +#define DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED (1 << 28) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_SHIFT (20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_MASK (0xf << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_IDLE (0 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_SYNC (1 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_START1 (2 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_COMMAND (3 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_ADDRESS (4 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_LENGTH (5 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_WRITE1 (6 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_READ1 (7 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_GET_M (8 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_STOP1 (9 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_STOP2 (10 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_REPLY (11 << 20) +#define DPAUX_DP_AUXSTAT_AUXCTL_STATE_CLEANUP (12 << 20) +#define DPAUX_DP_AUXSTAT_REPLYTYPE_SHIFT (16) +#define DPAUX_DP_AUXSTAT_REPLYTYPE_MASK (0xf << 16) +#define DPAUX_DP_AUXSTAT_REPLYTYPE_ACK (0 << 16) +#define DPAUX_DP_AUXSTAT_REPLYTYPE_NACK (1 << 16) +#define DPAUX_DP_AUXSTAT_REPLYTYPE_DEFER (2 << 16) +#define DPAUX_DP_AUXSTAT_REPLYTYPE_I2CNACK (4 << 16) +#define DPAUX_DP_AUXSTAT_REPLYTYPE_I2CDEFER (8 << 16) +#define DPAUX_DP_AUXSTAT_NO_STOP_ERROR_SHIFT (11) +#define DPAUX_DP_AUXSTAT_NO_STOP_ERROR_NOT_PENDING (0 << 11) +#define DPAUX_DP_AUXSTAT_NO_STOP_ERROR_PENDING (1 << 11) +#define DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_SHIFT (10) +#define DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_NOT_PENDING (0 << 10) +#define DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_PENDING (1 << 10) +#define DPAUX_DP_AUXSTAT_RX_ERROR_SHIFT (9) +#define DPAUX_DP_AUXSTAT_RX_ERROR_NOT_PENDING (0 << 9) +#define DPAUX_DP_AUXSTAT_RX_ERROR_PENDING (1 << 9) +#define DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_SHIFT (8) +#define DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_NOT_PENDING (0 << 8) +#define DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_PENDING (1 << 8) +#define DPAUX_DP_AUXSTAT_REPLY_M_SHIFT (0) +#define DPAUX_DP_AUXSTAT_REPLY_M_MASK (0xff << 0) +#define DPAUX_HPD_CONFIG (0x3d) +#define DPAUX_HPD_IRQ_CONFIG (0x41) +#define DPAUX_DP_AUX_CONFIG (0x45) +#define DPAUX_HYBRID_PADCTL (0x49) +#define DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV_SHIFT (15) +#define DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV_DISABLE (0 << 15) +#define DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV_ENABLE (1 << 15) +#define DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV_SHIFT (14) +#define DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV_DISABLE (0 << 14) +#define DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV_ENABLE (1 << 14) +#define DPAUX_HYBRID_PADCTL_AUX_CMH_SHIFT (12) +#define DPAUX_HYBRID_PADCTL_AUX_CMH_DEFAULT_MASK (0x3 << 12) +#define DPAUX_HYBRID_PADCTL_AUX_CMH_V0_60 (0 << 12) +#define DPAUX_HYBRID_PADCTL_AUX_CMH_V0_64 (1 << 12) +#define DPAUX_HYBRID_PADCTL_AUX_CMH_V0_70 (2 << 12) +#define DPAUX_HYBRID_PADCTL_AUX_CMH_V0_56 (3 << 12) +#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_SHIFT (8) +#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_DEFAULT_MASK (0x7 << 8) +#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_78 (0 << 8) +#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_60 (1 << 8) +#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_54 (2 << 8) +#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_45 (3 << 8) +#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_50 (4 << 8) +#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_42 (5 << 8) +#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_39 (6 << 8) +#define DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_34 (7 << 8) +#define DPAUX_HYBRID_PADCTL_AUX_DRVI_SHIFT (2) +#define DPAUX_HYBRID_PADCTL_AUX_DRVI_DEFAULT_MASK (0x3f << 2) +#define DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV_SHIFT (1) +#define DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV_DISABLE (0 << 1) +#define DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV_ENABLE (1 << 1) +#define DPAUX_HYBRID_PADCTL_MODE_SHIFT (0) +#define DPAUX_HYBRID_PADCTL_MODE_AUX (0) +#define DPAUX_HYBRID_PADCTL_MODE_I2C (1) +#define DPAUX_HYBRID_SPARE (0x4d) +#define DPAUX_HYBRID_SPARE_PAD_PWR_POWERUP (0) +#define DPAUX_HYBRID_SPARE_PAD_PWR_POWERDOWN (1) + +/* TODO: figure out which of the NV_ constants are the same as all the other + * display port standard constants. + */ + +#define DP_AUX_DEFER_MAX_TRIES 7 +#define DP_AUX_TIMEOUT_MAX_TRIES 2 +#define DP_POWER_ON_MAX_TRIES 3 +#define DP_CLOCK_RECOVERY_MAX_TRIES 7 +#define DP_CLOCK_RECOVERY_TOT_TRIES 15 + +#define DP_AUX_MAX_BYTES 16 + +#define DP_LCDVCC_TO_HPD_DELAY_MS 200 +#define DP_AUX_TIMEOUT_MS 40 +#define DP_DPCP_RETRY_SLEEP_NS 400 + +enum { + driveCurrent_Level0 = 0, + driveCurrent_Level1 = 1, + driveCurrent_Level2 = 2, + driveCurrent_Level3 = 3, +}; + +enum { + preEmphasis_Disabled = 0, + preEmphasis_Level1 = 1, + preEmphasis_Level2 = 2, + preEmphasis_Level3 = 3, +}; + +enum { + postCursor2_Level0 = 0, + postCursor2_Level1 = 1, + postCursor2_Level2 = 2, + postCursor2_Level3 = 3, + postCursor2_Supported +}; + + +/* the +10ms is the time for power rail going up from 10-90% or + 90%-10% on powerdown */ +/* Time from power-rail is turned on and aux/12c-over-aux is available */ +#define EDP_PWR_ON_TO_AUX_TIME_MS (200+10) +/* Time from power-rail is turned on and MainLink is available for LT */ +#define EDP_PWR_ON_TO_ML_TIME_MS (200+10) +/* Time from turning off power to turn-it on again (does not include post + poweron time) */ +#define EDP_PWR_OFF_TO_ON_TIME_MS (500+10) + +struct tegra_dc_dp_data { + struct tegra_dc *dc; + struct tegra_dc_sor_data *sor; + void *aux_base; + struct tegra_dc_mode *mode; + struct tegra_dc_dp_link_config link_cfg; +}; + + +/* DPCD definitions */ +/* you know, all the vendors pick their own set of defines. + * All of them. + * FIXME so we can use the ones in include/device/drm_dp_helper.h + */ +#define NV_DPCD_REV (0x00000000) +#define NV_DPCD_REV_MAJOR_SHIFT (4) +#define NV_DPCD_REV_MAJOR_MASK (0xf << 4) +#define NV_DPCD_REV_MINOR_SHIFT (0) +#define NV_DPCD_REV_MINOR_MASK (0xf) +#define NV_DPCD_MAX_LINK_BANDWIDTH (0x00000001) +#define NV_DPCD_MAX_LINK_BANDWIDTH_VAL_1_62_GPBS (0x00000006) +#define NV_DPCD_MAX_LINK_BANDWIDTH_VAL_2_70_GPBS (0x0000000a) +#define NV_DPCD_MAX_LINK_BANDWIDTH_VAL_5_40_GPBS (0x00000014) +#define NV_DPCD_MAX_LANE_COUNT (0x00000002) +#define NV_DPCD_MAX_LANE_COUNT_MASK (0x1f) +#define NV_DPCD_MAX_LANE_COUNT_LANE_1 (0x00000001) +#define NV_DPCD_MAX_LANE_COUNT_LANE_2 (0x00000002) +#define NV_DPCD_MAX_LANE_COUNT_LANE_4 (0x00000004) +#define NV_DPCD_MAX_LANE_COUNT_ENHANCED_FRAMING_NO (0x00000000 << 7) +#define NV_DPCD_MAX_LANE_COUNT_ENHANCED_FRAMING_YES (0x00000001 << 7) +#define NV_DPCD_MAX_DOWNSPREAD (0x00000003) +#define NV_DPCD_MAX_DOWNSPREAD_VAL_NONE (0x00000000) +#define NV_DPCD_MAX_DOWNSPREAD_VAL_0_5_PCT (0x00000001) +#define NV_DPCD_MAX_DOWNSPREAD_NO_AUX_HANDSHAKE_LT_F (0x00000000 << 6) +#define NV_DPCD_MAX_DOWNSPREAD_NO_AUX_HANDSHAKE_LT_T (0x00000001 << 6) +#define NV_DPCD_EDP_CONFIG_CAP (0x0000000D) +#define NV_DPCD_EDP_CONFIG_CAP_ASC_RESET_NO (0x00000000) +#define NV_DPCD_EDP_CONFIG_CAP_ASC_RESET_YES (0x00000001) +#define NV_DPCD_EDP_CONFIG_CAP_FRAMING_CHANGE_NO (0x00000000 << 1) +#define NV_DPCD_EDP_CONFIG_CAP_FRAMING_CHANGE_YES (0x00000001 << 1) +#define NV_DPCD_LINK_BANDWIDTH_SET (0x00000100) +#define NV_DPCD_LANE_COUNT_SET (0x00000101) +#define NV_DPCD_LANE_COUNT_SET_ENHANCEDFRAMING_F (0x00000000 << 7) +#define NV_DPCD_LANE_COUNT_SET_ENHANCEDFRAMING_T (0x00000001 << 7) +#define NV_DPCD_TRAINING_PATTERN_SET (0x00000102) +#define NV_DPCD_TRAINING_PATTERN_SET_TPS_MASK 0x3 +#define NV_DPCD_TRAINING_PATTERN_SET_TPS_NONE (0x00000000) +#define NV_DPCD_TRAINING_PATTERN_SET_TPS_TP1 (0x00000001) +#define NV_DPCD_TRAINING_PATTERN_SET_TPS_TP2 (0x00000002) +#define NV_DPCD_TRAINING_PATTERN_SET_TPS_TP3 (0x00000003) +#define NV_DPCD_TRAINING_PATTERN_SET_SC_DISABLED_F (0x00000000 << 5) +#define NV_DPCD_TRAINING_PATTERN_SET_SC_DISABLED_T (0x00000001 << 5) +#define NV_DPCD_TRAINING_LANE0_SET (0x00000103) +#define NV_DPCD_TRAINING_LANE1_SET (0x00000104) +#define NV_DPCD_TRAINING_LANE2_SET (0x00000105) +#define NV_DPCD_TRAINING_LANE3_SET (0x00000106) +#define NV_DPCD_TRAINING_LANEX_SET_DC_SHIFT 0 +#define NV_DPCD_TRAINING_LANEX_SET_DC_MAX_REACHED_T (0x00000001 << 2) +#define NV_DPCD_TRAINING_LANEX_SET_PE_SHIFT 3 +#define NV_DPCD_TRAINING_LANEX_SET_PE_MAX_REACHED_T (0x00000001 << 5) +#define NV_DPCD_DOWNSPREAD_CTRL (0x00000107) +#define NV_DPCD_DOWNSPREAD_CTRL_SPREAD_AMP_NONE (0x00000000 << 4) +#define NV_DPCD_DOWNSPREAD_CTRL_SPREAD_AMP_LT_0_5 (0x00000001 << 4) +#define NV_DPCD_MAIN_LINK_CHANNEL_CODING_SET (0x00000108) +#define NV_DPCD_MAIN_LINK_CHANNEL_CODING_SET_ANSI_8B10B 1 +#define NV_DPCD_EDP_CONFIG_SET (0x0000010A) +#define NV_DPCD_EDP_CONFIG_SET_ASC_RESET_DISABLE (0x00000000) +#define NV_DPCD_EDP_CONFIG_SET_ASC_RESET_ENABLE (0x00000001) +#define NV_DPCD_EDP_CONFIG_SET_FRAMING_CHANGE_DISABLE (0x00000000 << 1) +#define NV_DPCD_EDP_CONFIG_SET_FRAMING_CHANGE_ENABLE (0x00000001 << 1) +#define NV_DPCD_TRAINING_LANE0_1_SET2 (0x0000010F) +#define NV_DPCD_TRAINING_LANE2_3_SET2 (0x00000110) +#define NV_DPCD_LANEX_SET2_PC2_SHIFT 0 +#define NV_DPCD_LANEX_SET2_PC2_MAX_REACHED_T (0x00000001 << 2) +#define NV_DPCD_LANEXPLUS1_SET2_PC2_SHIFT 4 +#define NV_DPCD_LANEXPLUS1_SET2_PC2_MAX_REACHED_T (0x00000001 << 6) +#define NV_DPCD_SINK_COUNT (0x00000200) +#define NV_DPCD_DEVICE_SERVICE_IRQ_VECTOR (0x00000201) +#define NV_DPCD_DEVICE_SERVICE_IRQ_VECTOR_AUTO_TEST_NO (0x00000000 << 1) +#define NV_DPCD_DEVICE_SERVICE_IRQ_VECTOR_AUTO_TEST_YES (0x00000001 << 1) +#define NV_DPCD_DEVICE_SERVICE_IRQ_VECTOR_CP_NO (0x00000000 << 2) +#define NV_DPCD_DEVICE_SERVICE_IRQ_VECTOR_CP_YES (0x00000001 << 2) +#define NV_DPCD_LANE0_1_STATUS (0x00000202) +#define NV_DPCD_LANE2_3_STATUS (0x00000203) +#define NV_DPCD_STATUS_LANEX_CR_DONE_SHIFT 0 +#define NV_DPCD_STATUS_LANEX_CR_DONE_NO (0x00000000) +#define NV_DPCD_STATUS_LANEX_CR_DONE_YES (0x00000001) +#define NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_SHIFT 1 +#define NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_NO (0x00000000 << 1) +#define NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_YES (0x00000001 << 1) +#define NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_SHFIT 2 +#define NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_NO (0x00000000 << 2) +#define NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_YES (0x00000001 << 2) +#define NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_SHIFT 4 +#define NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_NO (0x00000000 << 4) +#define NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_YES (0x00000001 << 4) +#define NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_SHIFT 5 +#define NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_NO (0x00000000 << 5) +#define NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_YES (0x00000001 << 5) +#define NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_SHIFT 6 +#define NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_NO (0x00000000 << 6) +#define NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_YES (0x00000001 << 6) +#define NV_DPCD_LANE_ALIGN_STATUS_UPDATED (0x00000204) +#define NV_DPCD_LANE_ALIGN_STATUS_UPDATED_DONE_NO (0x00000000) +#define NV_DPCD_LANE_ALIGN_STATUS_UPDATED_DONE_YES (0x00000001) +#define NV_DPCD_LANE0_1_ADJUST_REQ (0x00000206) +#define NV_DPCD_LANE2_3_ADJUST_REQ (0x00000207) +#define NV_DPCD_ADJUST_REQ_LANEX_DC_SHIFT 0 +#define NV_DPCD_ADJUST_REQ_LANEX_DC_MASK 0x3 +#define NV_DPCD_ADJUST_REQ_LANEX_PE_SHIFT 2 +#define NV_DPCD_ADJUST_REQ_LANEX_PE_MASK (0x3 << 2) +#define NV_DPCD_ADJUST_REQ_LANEXPLUS1_DC_SHIFT 4 +#define NV_DPCD_ADJUST_REQ_LANEXPLUS1_DC_MASK (0x3 << 4) +#define NV_DPCD_ADJUST_REQ_LANEXPLUS1_PE_SHIFT 6 +#define NV_DPCD_ADJUST_REQ_LANEXPLUS1_PE_MASK (0x3 << 6) +#define NV_DPCD_ADJUST_REQ_POST_CURSOR2 (0x0000020C) +#define NV_DPCD_ADJUST_REQ_POST_CURSOR2_LANE_MASK 0x3 +#define NV_DPCD_ADJUST_REQ_POST_CURSOR2_LANE_SHIFT(i) (i*2) +#define NV_DPCD_TEST_REQUEST (0x00000218) +#define NV_DPCD_SOURCE_IEEE_OUI (0x00000300) +#define NV_DPCD_SINK_IEEE_OUI (0x00000400) +#define NV_DPCD_BRANCH_IEEE_OUI (0x00000500) +#define NV_DPCD_SET_POWER (0x00000600) +#define NV_DPCD_SET_POWER_VAL_RESERVED (0x00000000) +#define NV_DPCD_SET_POWER_VAL_D0_NORMAL (0x00000001) +#define NV_DPCD_SET_POWER_VAL_D3_PWRDWN (0x00000002) +#define NV_DPCD_HDCP_BKSV_OFFSET (0x00068000) +#define NV_DPCD_HDCP_RPRIME_OFFSET (0x00068005) +#define NV_DPCD_HDCP_AKSV_OFFSET (0x00068007) +#define NV_DPCD_HDCP_AN_OFFSET (0x0006800C) +#define NV_DPCD_HDCP_VPRIME_OFFSET (0x00068014) +#define NV_DPCD_HDCP_BCAPS_OFFSET (0x00068028) +#define NV_DPCD_HDCP_BSTATUS_OFFSET (0x00068029) +#define NV_DPCD_HDCP_BINFO_OFFSET (0x0006802A) +#define NV_DPCD_HDCP_KSV_FIFO_OFFSET (0x0006802C) +#define NV_DPCD_HDCP_AINFO_OFFSET (0x0006803B) + +int tegra_dc_dpaux_read(struct tegra_dc_dp_data *dp, u32 cmd, u32 addr, + u8 *data, u32 *size, u32 *aux_stat); +int dpaux_write(u32 addr, u32 size, u32 data); +int dpaux_read(u32 addr, u32 size, u8 *data); +void debug_dpaux_print(u32 addr, u32 size); +void dp_link_training(u32 lanes, u32 speed); +#endif /* __SOC_NVIDIA_TEGRA_DISPLAYPORT_H__ */ diff --git a/src/soc/nvidia/tegra/dp.c b/src/soc/nvidia/tegra/dp.c new file mode 100644 index 0000000000..537c56ccf7 --- /dev/null +++ b/src/soc/nvidia/tegra/dp.c @@ -0,0 +1,724 @@ +/* + * drivers/video/tegra/dc/dp.c + * + * Copyright (c) 2011-2013, NVIDIA Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "i2c.h" +#include "dc.h" +/* shit. This is broken. */ +#include +// this is really broken. #include +#include + +#undef DEBUG +extern int dump; +unsigned long READL(void* p); +void WRITEL(unsigned long value, void* p); + +static inline u32 tegra_dpaux_readl(struct tegra_dc_dp_data *dp, u32 reg) +{ + void *addr = dp->aux_base + (u32)(reg <<2); + u32 reg_val = READL(addr); +#ifdef DEBUG + + printk(BIOS_SPEW, "JZ: %s: reg: %p, val: %#x\n", __func__, + addr, reg_val); +#endif + return reg_val; +} + +static inline void tegra_dpaux_writel(struct tegra_dc_dp_data *dp, + u32 reg, u32 val) +{ + void *addr = dp->aux_base + (u32)(reg <<2); +#ifdef DEBUG + printk(BIOS_SPEW, "JZ: %s: reg: %p, val: %#x\n", __func__, + addr, val); +#endif + WRITEL(val, addr); +} + + +static inline u32 tegra_dc_dpaux_poll_register(struct tegra_dc_dp_data *dp, + u32 reg, u32 mask, u32 exp_val, u32 poll_interval_us, u32 timeout_ms) +{ +// unsigned long timeout_jf = jiffies + msecs_to_jiffies(timeout_ms); + u32 reg_val = 0; + + printk(BIOS_SPEW, "JZ: %s: enter, poll_reg: %#x: timeout: 0x%x\n", + __func__, reg*4, timeout_ms); + do { +// udelay(poll_interval_us); + udelay(1); + reg_val = tegra_dpaux_readl(dp, reg); + } while (((reg_val & mask) != exp_val) && (--timeout_ms > 0)); + + if ((reg_val & mask) == exp_val) + return 0; /* success */ + printk(BIOS_SPEW,"dpaux_poll_register 0x%x: timeout: (reg_val)0x%08x & (mask)0x%08x != (exp_val)0x%08x\n", reg, reg_val, mask, exp_val); + return timeout_ms; +} + + +static inline int tegra_dpaux_wait_transaction(struct tegra_dc_dp_data *dp) +{ + /* According to DP spec, each aux transaction needs to finish + within 40ms. */ + if (tegra_dc_dpaux_poll_register(dp, DPAUX_DP_AUXCTL, + DPAUX_DP_AUXCTL_TRANSACTREQ_MASK, + DPAUX_DP_AUXCTL_TRANSACTREQ_DONE, + 100, DP_AUX_TIMEOUT_MS*1000) != 0) { + printk(BIOS_SPEW,"dp: DPAUX transaction timeout\n"); + return -1; + } + return 0; +} + +static int tegra_dc_dpaux_write_chunk(struct tegra_dc_dp_data *dp, u32 cmd, + u32 addr, u8 *data, u32 *size, u32 *aux_stat) +{ + int i; + u32 reg_val; + u32 timeout_retries = DP_AUX_TIMEOUT_MAX_TRIES; + u32 defer_retries = DP_AUX_DEFER_MAX_TRIES; + u32 temp_data; + + if (*size > DP_AUX_MAX_BYTES) + return -1; /* only write one chunk of data */ + + /* Make sure the command is write command */ + switch (cmd) { + case DPAUX_DP_AUXCTL_CMD_I2CWR: + case DPAUX_DP_AUXCTL_CMD_MOTWR: + case DPAUX_DP_AUXCTL_CMD_AUXWR: + break; + default: + printk(BIOS_SPEW,"dp: aux write cmd 0x%x is invalid\n", + cmd); + return -1; + } + +#if 0 +/* interesting. */ + if (tegra_platform_is_silicon()) { + *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT); + if (!(*aux_stat & DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)) { + printk(BIOS_SPEW,"dp: HPD is not detected\n"); + return -EFAULT; + } + } +#endif + + tegra_dpaux_writel(dp, DPAUX_DP_AUXADDR, addr); + for (i = 0; i < DP_AUX_MAX_BYTES/4; ++i) { + memcpy(&temp_data, data, 4); + tegra_dpaux_writel(dp, DPAUX_DP_AUXDATA_WRITE_W(i), + temp_data); + data += 4; + } + + reg_val = tegra_dpaux_readl(dp, DPAUX_DP_AUXCTL); + reg_val &= ~DPAUX_DP_AUXCTL_CMD_MASK; + reg_val |= cmd; + reg_val &= ~DPAUX_DP_AUXCTL_CMDLEN_FIELD; + reg_val |= ((*size-1) << DPAUX_DP_AUXCTL_CMDLEN_SHIFT); + + while ((timeout_retries > 0) && (defer_retries > 0)) { + if ((timeout_retries != DP_AUX_TIMEOUT_MAX_TRIES) || + (defer_retries != DP_AUX_DEFER_MAX_TRIES)) + udelay(1); + + reg_val |= DPAUX_DP_AUXCTL_TRANSACTREQ_PENDING; + tegra_dpaux_writel(dp, DPAUX_DP_AUXCTL, reg_val); + + if (tegra_dpaux_wait_transaction(dp)) + printk(BIOS_SPEW,"dp: aux write transaction timeout\n"); + + *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT); + // printk(BIOS_SPEW, "dp: %s: aux stat: 0x%08x\n", __func__, *aux_stat); + + /* Ignore I2C errors on fpga */ + if ((*aux_stat & DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_PENDING) || + (*aux_stat & DPAUX_DP_AUXSTAT_RX_ERROR_PENDING) || + (*aux_stat & DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_PENDING) || + (*aux_stat & DPAUX_DP_AUXSTAT_NO_STOP_ERROR_PENDING)) { + if (timeout_retries-- > 0) { + printk(BIOS_SPEW,"dp: aux write retry (0x%x) -- %d\n", + *aux_stat, timeout_retries); + /* clear the error bits */ + tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT, + *aux_stat); + continue; + } else { + printk(BIOS_SPEW,"dp: aux write got error (0x%x)\n", + *aux_stat); + return -1; + } + } + + if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_I2CDEFER) || + (*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_DEFER)) { + if (defer_retries-- > 0) { + printk(BIOS_SPEW, "dp: aux write defer (0x%x) -- %d\n", + *aux_stat, defer_retries); + /* clear the error bits */ + tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT, + *aux_stat); + continue; + } else { + printk(BIOS_SPEW, "dp: aux write defer exceeds max retries " + "(0x%x)\n", + *aux_stat); + return -1; + } + } + + if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_MASK) == + DPAUX_DP_AUXSTAT_REPLYTYPE_ACK) { + *size = ((*aux_stat) & DPAUX_DP_AUXSTAT_REPLY_M_MASK); + return 0; + } else { + printk(BIOS_SPEW,"dp: aux write failed (0x%x)\n", *aux_stat); + return -1; + } + } + /* Should never come to here */ + return -1; +} + +static int tegra_dc_dpaux_write(struct tegra_dc_dp_data *dp, u32 cmd, u32 addr, + u8 *data, u32 *size, u32 *aux_stat) +{ + u32 cur_size = 0; + u32 finished = 0; + u32 cur_left; + int ret = 0; + + do { + cur_size = *size - finished; + if (cur_size > DP_AUX_MAX_BYTES) + cur_size = DP_AUX_MAX_BYTES; + cur_left = cur_size; + ret = tegra_dc_dpaux_write_chunk(dp, cmd, addr, + data, &cur_left, aux_stat); + + cur_size -= cur_left; + finished += cur_size; + addr += cur_size; + data += cur_size; + + if (ret) + break; + } while (*size > finished); + + *size = finished; + return ret; +} + +static int tegra_dc_dpaux_read_chunk(struct tegra_dc_dp_data *dp, u32 cmd, + u32 addr, u8 *data, u32 *size, u32 *aux_stat) +{ + u32 reg_val; + u32 timeout_retries = DP_AUX_TIMEOUT_MAX_TRIES; + u32 defer_retries = DP_AUX_DEFER_MAX_TRIES; + + if (*size > DP_AUX_MAX_BYTES) + return -1; /* only read one chunk */ + + /* Check to make sure the command is read command */ + switch (cmd) { + case DPAUX_DP_AUXCTL_CMD_I2CRD: + case DPAUX_DP_AUXCTL_CMD_I2CREQWSTAT: + case DPAUX_DP_AUXCTL_CMD_MOTRD: + case DPAUX_DP_AUXCTL_CMD_AUXRD: + break; + default: + printk(BIOS_SPEW,"dp: aux read cmd 0x%x is invalid\n", cmd); + return -1; + } + +if (0){ + *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT); + if (!(*aux_stat & DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)) { + printk(BIOS_SPEW,"dp: HPD is not detected\n"); + //return EFAULT; + } + } + + tegra_dpaux_writel(dp, DPAUX_DP_AUXADDR, addr); + + reg_val = tegra_dpaux_readl(dp, DPAUX_DP_AUXCTL); + reg_val &= ~DPAUX_DP_AUXCTL_CMD_MASK; + reg_val |= cmd; + printk(BIOS_SPEW, "cmd = %08x\n", reg_val); + reg_val &= ~DPAUX_DP_AUXCTL_CMDLEN_FIELD; + reg_val |= ((*size-1) << DPAUX_DP_AUXCTL_CMDLEN_SHIFT); + printk(BIOS_SPEW, "cmd = %08x\n", reg_val); + while ((timeout_retries > 0) && (defer_retries > 0)) { + if ((timeout_retries != DP_AUX_TIMEOUT_MAX_TRIES) || + (defer_retries != DP_AUX_DEFER_MAX_TRIES)) + udelay(DP_DPCP_RETRY_SLEEP_NS * 2); + + reg_val |= DPAUX_DP_AUXCTL_TRANSACTREQ_PENDING; + printk(BIOS_SPEW, "cmd = %08x\n", reg_val); + tegra_dpaux_writel(dp, DPAUX_DP_AUXCTL, reg_val); + + if (tegra_dpaux_wait_transaction(dp)) + printk(BIOS_SPEW,"dp: aux read transaction timeout\n"); + + *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT); + printk(BIOS_SPEW, "dp: %s: aux stat: 0x%08x\n", __func__, *aux_stat); + + if ((*aux_stat & DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_PENDING) || + (*aux_stat & DPAUX_DP_AUXSTAT_RX_ERROR_PENDING) || + (*aux_stat & DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_PENDING) || + (*aux_stat & DPAUX_DP_AUXSTAT_NO_STOP_ERROR_PENDING)) { + if (timeout_retries-- > 0) { + printk(BIOS_SPEW, "dp: aux read retry (0x%x) -- %d\n", + *aux_stat, timeout_retries); + /* clear the error bits */ + tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT, + *aux_stat); + continue; /* retry */ + } else { + printk(BIOS_SPEW,"dp: aux read got error (0x%x)\n", + *aux_stat); + return -1; + } + } + + if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_I2CDEFER) || + (*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_DEFER)) { + if (defer_retries-- > 0) { + printk(BIOS_SPEW, "dp: aux read defer (0x%x) -- %d\n", + *aux_stat, defer_retries); + /* clear the error bits */ + tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT, + *aux_stat); + continue; + } else { + printk(BIOS_SPEW,"dp: aux read defer exceeds max retries " + "(0x%x)\n", *aux_stat); + return -1; + } + } + + if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_MASK) == + DPAUX_DP_AUXSTAT_REPLYTYPE_ACK) { + int i; + u32 temp_data[4]; + + for (i = 0; i < DP_AUX_MAX_BYTES/4; ++i) + temp_data[i] = tegra_dpaux_readl(dp, + DPAUX_DP_AUXDATA_READ_W(i)); + + *size = ((*aux_stat) & DPAUX_DP_AUXSTAT_REPLY_M_MASK); + printk(BIOS_SPEW, "dp: aux read data %d bytes\n", *size); + memcpy(data, temp_data, *size); + + return 0; + } else { + printk(BIOS_SPEW,"dp: aux read failed (0x%x\n", *aux_stat); + return -1; + } + } + /* Should never come to here */ + printk(BIOS_SPEW, "%s: can't\n", __func__); + return -1; +} + +int tegra_dc_dpaux_read(struct tegra_dc_dp_data *dp, u32 cmd, u32 addr, + u8 *data, u32 *size, u32 *aux_stat) +{ + u32 finished = 0; + u32 cur_size; + int ret = 0; + + do { + cur_size = *size - finished; + if (cur_size > DP_AUX_MAX_BYTES) + cur_size = DP_AUX_MAX_BYTES; + + ret = tegra_dc_dpaux_read_chunk(dp, cmd, addr, + data, &cur_size, aux_stat); + + /* cur_size should be the real size returned */ + addr += cur_size; + data += cur_size; + finished += cur_size; + + if (ret) + break; + +#if 0 + if (cur_size == 0) { + printk(BIOS_SPEW,"JZ: no data found, ret\n"); + break; + } +#endif + } while (*size > finished); + + *size = finished; + return ret; +} + +static int tegra_dc_dp_dpcd_read(struct tegra_dc_dp_data *dp, u32 cmd, + u8 *data_ptr) +{ + u32 size = 1; + u32 status = 0; + int ret; + + ret = tegra_dc_dpaux_read_chunk(dp, DPAUX_DP_AUXCTL_CMD_AUXRD, + cmd, data_ptr, &size, &status); + if (ret) + printk(BIOS_SPEW,"dp: Failed to read DPCD data. CMD 0x%x, Status 0x%x\n", + cmd, status); + + return ret; +} + +#if 0 +static void tegra_dc_dpaux_enable(struct tegra_dc_dp_data *dp) +{ + /* clear interrupt */ + tegra_dpaux_writel(dp, DPAUX_INTR_AUX, 0xffffffff); + /* do not enable interrupt for now. Enable them when Isr in place */ + tegra_dpaux_writel(dp, DPAUX_INTR_EN_AUX, 0x0); + + tegra_dpaux_writel(dp, DPAUX_HYBRID_PADCTL, + DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_50 | + DPAUX_HYBRID_PADCTL_AUX_CMH_V0_70 | + 0x18 << DPAUX_HYBRID_PADCTL_AUX_DRVI_SHIFT | + DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV_ENABLE); +} + +static int tegra_dc_dp_lower_config(struct tegra_dc_dp_data *dp, + struct tegra_dc_dp_link_config *cfg) +{ + if (cfg->link_bw == SOR_LINK_SPEED_G1_62) { + if (cfg->max_link_bw > SOR_LINK_SPEED_G1_62) + cfg->link_bw = SOR_LINK_SPEED_G2_7; + cfg->lane_count /= 2; + } else if (cfg->link_bw == SOR_LINK_SPEED_G2_7) + cfg->link_bw = SOR_LINK_SPEED_G1_62; + else if (cfg->link_bw == SOR_LINK_SPEED_G5_4) { + if (cfg->lane_count == 1) { + cfg->link_bw = SOR_LINK_SPEED_G2_7; + cfg->lane_count = cfg->max_lane_count; + } else + cfg->lane_count /= 2; + } else { + printk(BIOS_ERR, + "dp: Error link rate %d\n", cfg->link_bw); + return 0; + } + return (cfg->lane_count > 0); +} + +#endif +static int tegra_dc_dp_init_max_link_cfg(struct tegra_dc_dp_data *dp, + struct tegra_dc_dp_link_config *cfg) +{ + u8 dpcd_data; + int ret; + + ret = tegra_dc_dp_dpcd_read(dp, NV_DPCD_MAX_LANE_COUNT, + &dpcd_data); + if (ret) + return ret; + + cfg->max_lane_count = dpcd_data & NV_DPCD_MAX_LANE_COUNT_MASK; + printk(BIOS_SPEW, "JZ: %s: max_lane_count: %d\n", __func__, cfg->max_lane_count); + + cfg->support_enhanced_framing = + (dpcd_data & NV_DPCD_MAX_LANE_COUNT_ENHANCED_FRAMING_YES) ? + 1 : 0; + printk(BIOS_SPEW, "JZ: %s: enh-framing: %d\n", __func__, cfg->support_enhanced_framing); + + ret = tegra_dc_dp_dpcd_read(dp, NV_DPCD_MAX_DOWNSPREAD, + &dpcd_data); + if (ret) + return ret; + cfg->downspread = (dpcd_data & NV_DPCD_MAX_DOWNSPREAD_VAL_0_5_PCT) ? + 1 : 0; + printk(BIOS_SPEW, "JZ: %s: downspread: %d\n", __func__, cfg->downspread); + + ret = tegra_dc_dp_dpcd_read(dp, NV_DPCD_MAX_LINK_BANDWIDTH, + &cfg->max_link_bw); + if (ret) + return ret; + printk(BIOS_SPEW, "JZ: %s: max_link_bw: %d\n", __func__, cfg->max_link_bw); + + // jz, changed + // cfg->bits_per_pixel = dp->dc->pdata->default_out->depth; + cfg->bits_per_pixel = 24; + + /* TODO: need to come from the board file */ + /* Venice2 settings */ + cfg->drive_current = 0x20202020; + cfg->preemphasis = 0; + cfg->postcursor = 0; + + ret = tegra_dc_dp_dpcd_read(dp, NV_DPCD_EDP_CONFIG_CAP, + &dpcd_data); + if (ret) + return ret; + cfg->alt_scramber_reset_cap = + (dpcd_data & NV_DPCD_EDP_CONFIG_CAP_ASC_RESET_YES) ? + 1 : 0; + cfg->only_enhanced_framing = + (dpcd_data & NV_DPCD_EDP_CONFIG_CAP_FRAMING_CHANGE_YES) ? + 1 : 0; + printk(BIOS_SPEW, "JZ: %s: alt_reset_cap: %d, only_enh_framing: %d\n", __func__, + cfg->alt_scramber_reset_cap, cfg->only_enhanced_framing); + + cfg->lane_count = cfg->max_lane_count; + cfg->link_bw = cfg->max_link_bw; + cfg->enhanced_framing = cfg->support_enhanced_framing; + +#if 0 // jz + tegra_dc_dp_calc_config(dp, dp->mode, cfg); + return 0; +#else +// return -1; // do link_training + return 0; // do link_training +#endif // jz +} + + +#if 0 +static int tegra_dc_dp_explore_link_cfg(struct tegra_dc_dp_data *dp, + struct tegra_dc_dp_link_config *cfg, struct tegra_dc_mode *mode) +{ + struct tegra_dc_dp_link_config temp_cfg; +#if 0 + /* kernel thing. */ + if (!mode->pclk || !mode->h_active || !mode->v_active) { + dev_err(&dp->dc->ndev->dev, + "dp: error mode configuration"); + return -EINVAL; + } +#endif + if (!cfg->max_link_bw || !cfg->max_lane_count) { + printk(BIOS_SPEW, + "dp: error link configuration"); + return -1; + } + + cfg->is_valid = 0; + memcpy(&temp_cfg, cfg, sizeof(temp_cfg)); + + temp_cfg.link_bw = temp_cfg.max_link_bw; + temp_cfg.lane_count = temp_cfg.max_lane_count; + + while (tegra_dc_dp_calc_config(dp, mode, &temp_cfg) && + tegra_dp_link_config(dp, &temp_cfg)) { + /* current link cfg is doable */ + memcpy(cfg, &temp_cfg, sizeof(temp_cfg)); + + /* try to lower the config */ + if (!tegra_dc_dp_lower_config(dp, &temp_cfg)) + break; + } + + return cfg->is_valid ? 0 : -1; +} +#endif +#if 0 +static long tegra_dc_dp_setup_clk(struct tegra_dc *dc, struct clk *clk) +{ + struct tegra_dc_dp_data *dp = tegra_dc_get_outdata(dc); + struct clk *sor_clk = dp->sor->sor_clk; + struct clk *parent_clk; + + if (clk == dc->clk) { + parent_clk = clk_get_sys(NULL, + dc->out->parent_clk ? : "pll_d_out0"); + if (clk_get_parent(clk) != parent_clk) + clk_set_parent(clk, parent_clk); + } + + tegra_dc_sor_setup_clk(dp->sor, clk, false); + + parent_clk = clk_get(NULL, "pll_dp"); + + if (clk_get_parent(sor_clk) != parent_clk) + clk_set_parent(sor_clk, parent_clk); + clk_set_rate(parent_clk, 270000000); + + if (!tegra_is_clk_enabled(parent_clk)) + clk_prepare_enable(parent_clk); + + return tegra_dc_pclk_round_rate(dc, dp->sor->dc->mode.pclk); +} + +#endif +//struct tegra_dc dc_data = {0}; +struct tegra_dc_sor_data sor_data = {0}; +struct tegra_dc_dp_data dp_data = {0}; + +static int tegra_dc_dpcd_read_rev(struct tegra_dc_dp_data *dp, + u8 *rev) +{ + u32 size; + int ret; + u32 status = 0; + + size = 3; + ret = tegra_dc_dpaux_read(dp, DPAUX_DP_AUXCTL_CMD_AUXRD, + NV_DPCD_REV, rev, &size, &status); + if (ret) { + printk(BIOS_SPEW,"dp: Failed to read NV_DPCD_REV\n"); + return ret; + } + return 0; +} +u32 dp_setup_timing(u32 panel_id, u32 width, u32 height); +void dp_bringup(u32 winb_addr) +{ + struct tegra_dc_dp_data *dp = &dp_data; + + u32 dpcd_rev; + u32 pclk_freq; +// int ret; + + printk(BIOS_SPEW, "JZ: %s: entry\n",__func__); + + dp->sor = &sor_data; +// dp->sor->dc = dc; + dp->sor->base = (void *)TEGRA_ARM_SOR; +// dp->sor->base_res = base_res; +// dp->sor->sor_clk = clk; + dp->sor->link_cfg = &dp->link_cfg; + dp->sor->portnum = 0; + + dp->aux_base = (void *)TEGRA_ARM_DPAUX; +/* dp->mode = 0; */ /* ???? */ + + /* read panel info */ + if (!tegra_dc_dpcd_read_rev(dp, (u8 *)&dpcd_rev)) { + printk(BIOS_SPEW,"PANEL info: \n"); + printk(BIOS_SPEW,"--DPCP version(%#x): %d.%d\n", + dpcd_rev, (dpcd_rev >> 4)&0x0f, (dpcd_rev & 0x0f)); + } + + if (tegra_dc_dp_init_max_link_cfg(dp, &dp->link_cfg)) + printk(BIOS_SPEW,"dp: failed to init link configuration\n"); +#if 0 + if (tegra_dc_dp_link_training(dp, &dp->link_cfg)) + printk(BIOS_SPEW,"dp: failed to do lt\n"); +#endif + + dp_link_training((u32)(dp->link_cfg.lane_count), + (u32)(dp->link_cfg.link_bw)); + + pclk_freq = dp_setup_timing(5, 2560, 1700); // W: 2560, H: 1700, use_plld2: 1 + printk(BIOS_SPEW, "JZ: %s: pclk_freq: %d\n",__func__, pclk_freq); + +// void dp_misc_setting(u32 panel_bpp, u32 width, u32 height, u32 winb_addr) +void dp_misc_setting(u32 panel_bpp, u32 width, u32 height, u32 winb_addr, + u32 lane_count, u32 enhanced_framing, u32 panel_edp, + u32 pclkfreq, u32 linkfreq); + + dp_misc_setting(dp->link_cfg.bits_per_pixel, + 2560, 1700, winb_addr, + (u32)dp->link_cfg.lane_count, + (u32)dp->link_cfg.enhanced_framing, + (u32)dp->link_cfg.alt_scramber_reset_cap, + pclk_freq, + dp->link_cfg.link_bw * 27); + void dp_test(void); + //dp_test(); + + +#if 0 // jz, next + else if (tegra_dc_dp_explore_link_cfg(dp, &dp->link_cfg, + dp->mode)) + printk(BIOS_SPEW,"dp irq: cannot get working config\n"); + +// if (tegra_dp_link_config(dp, &dp->link_cfg)) +// printk(BIOS_SPEW,"dp: failed to set link configuration\n"); +#endif // rgm +} + +void debug_dpaux_print(u32 addr, u32 size) +{ + struct tegra_dc_dp_data *dp = &dp_data; + u32 status = 0; + u8 buf[16]; + int i; + + if ((size == 0) || (size > 16)) { + printk(BIOS_SPEW,"dp: %s: invalid size %d\n", __func__, size); + return; + } + + if (tegra_dc_dpaux_read(dp, DPAUX_DP_AUXCTL_CMD_AUXRD, + addr, buf, &size, &status)) { + printk(BIOS_SPEW,"******AuxRead Error: 0x%04x: status 0x%08x\n", addr, status); + return; + } + printk(BIOS_SPEW, "%s: addr: 0x%04x, size: %d\n", __func__, addr, size); + for (i=0; i < size; ++i) + printk(BIOS_SPEW," %02x", buf[i]); + + printk(BIOS_SPEW,"\n"); +} + +int dpaux_read(u32 addr, u32 size, u8 *data) +{ + + struct tegra_dc_dp_data *dp = &dp_data; + u32 status = 0; + + if ((size == 0) || (size > 16)) { + printk(BIOS_SPEW,"dp: %s: invalid size %d\n", __func__, size); + return -1; + } + + if (tegra_dc_dpaux_read(dp, DPAUX_DP_AUXCTL_CMD_AUXRD, + addr, data, &size, &status)) { + printk(BIOS_SPEW,"dp: Failed to read reg %#x, status: %#x\n", addr, status); + return -1; + } + + return 0; +} + +int dpaux_write(u32 addr, u32 size, u32 data) +{ + struct tegra_dc_dp_data *dp = &dp_data; + u32 status = 0; + int ret; + + printk(BIOS_SPEW, "JZ: %s: entry, addr: 0x%08x, size: 0x%08x, data: %#x\n", + __func__, addr, size, data); + + ret = tegra_dc_dpaux_write(dp, DPAUX_DP_AUXCTL_CMD_AUXWR, + addr, (u8 *)&data, &size, &status); + if (ret) + printk(BIOS_SPEW,"dp: Failed to write to reg %#x, status: 0x%x\n", + addr, status); + return ret; +} + diff --git a/src/soc/nvidia/tegra124/Makefile.inc b/src/soc/nvidia/tegra124/Makefile.inc index b16f1acd50..ceb32d72aa 100644 --- a/src/soc/nvidia/tegra124/Makefile.inc +++ b/src/soc/nvidia/tegra124/Makefile.inc @@ -39,12 +39,14 @@ ramstage-y += cbfs.c ramstage-y += cbmem.c ramstage-y += cpug.S ramstage-y += clock.c -ramstage-y += display.c +ramstage-y += display.c displayhack.c ramstage-y += dma.c ramstage-y += i2c.c ramstage-y += monotonic_timer.c ramstage-y += soc.c +ramstage-y += sor.c ramstage-y += spi.c +ramstage-y += ../tegra/dp.c ramstage-y += ../tegra/gpio.c ramstage-y += ../tegra/i2c.c ramstage-y += ../tegra/pinmux.c diff --git a/src/soc/nvidia/tegra124/display.c b/src/soc/nvidia/tegra124/display.c index 2eb02965b8..bb63f4605a 100644 --- a/src/soc/nvidia/tegra124/display.c +++ b/src/soc/nvidia/tegra124/display.c @@ -30,11 +30,31 @@ #include #include #include +#include #include #include #include "chip.h" #include +int dump = 0; +unsigned long READL(void * p); +void WRITEL(unsigned long value, void * p); +unsigned long READL(void * p) +{ + unsigned long value = readl(p); + if (dump) + printk(BIOS_SPEW, "readl %p %08lx\n", p, value); + return value; +} + + +void WRITEL(unsigned long value, void * p) +{ + if (dump) + printk(BIOS_SPEW, "writel %p %08lx\n", p, value); + writel(value, p); +} + static const u32 rgb_enb_tab[PIN_REG_COUNT] = { 0x00000000, 0x00000000, @@ -73,25 +93,25 @@ static int update_display_mode(struct dc_disp_reg *disp, u32 rate; u32 div; - writel(0x0, &disp->disp_timing_opt); + WRITEL(0x0, &disp->disp_timing_opt); - writel(config->vref_to_sync << 16 | config->href_to_sync, + WRITEL(config->vref_to_sync << 16 | config->href_to_sync, &disp->ref_to_sync); - writel(config->vsync_width << 16 | config->hsync_width, &disp->sync_width); - writel(config->vback_porch << 16 | config->hback_porch, &disp->back_porch); - writel(config->vfront_porch << 16 | config->hfront_porch, + WRITEL(config->vsync_width << 16 | config->hsync_width, &disp->sync_width); + WRITEL(config->vback_porch << 16 | config->hback_porch, &disp->back_porch); + WRITEL(config->vfront_porch << 16 | config->hfront_porch, &disp->front_porch); - writel(config->xres | (config->yres << 16), &disp->disp_active); + WRITEL(config->xres | (config->yres << 16), &disp->disp_active); val = DE_SELECT_ACTIVE << DE_SELECT_SHIFT; val |= DE_CONTROL_NORMAL << DE_CONTROL_SHIFT; - writel(val, &disp->data_enable_opt); + WRITEL(val, &disp->data_enable_opt); val = DATA_FORMAT_DF1P1C << DATA_FORMAT_SHIFT; val |= DATA_ALIGNMENT_MSB << DATA_ALIGNMENT_SHIFT; val |= DATA_ORDER_RED_BLUE << DATA_ORDER_SHIFT; - writel(val, &disp->disp_interface_ctrl); + WRITEL(val, &disp->disp_interface_ctrl); /* * The pixel clock divider is in 7.1 format (where the bottom bit @@ -104,11 +124,11 @@ static int update_display_mode(struct dc_disp_reg *disp, div = ((rate * 2 + config->pixel_clock / 2) / config->pixel_clock) - 2; printk(BIOS_SPEW, "Display clock %d, divider %d\n", rate, div); - writel(0x00010001, &disp->shift_clk_opt); + WRITEL(0x00010001, &disp->shift_clk_opt); val = PIXEL_CLK_DIVIDER_PCD1 << PIXEL_CLK_DIVIDER_SHIFT; val |= div << SHIFT_CLK_DIVIDER_SHIFT; - writel(val, &disp->disp_clk_ctrl); + WRITEL(val, &disp->disp_clk_ctrl); return 0; } @@ -154,55 +174,55 @@ static void update_window(struct display_controller *dc, u32 h_dda, v_dda; u32 val; - val = readl(&dc->cmd.disp_win_header); + val = READL(&dc->cmd.disp_win_header); val |= WINDOW_A_SELECT; - writel(val, &dc->cmd.disp_win_header); + WRITEL(val, &dc->cmd.disp_win_header); - writel(win->fmt, &dc->win.color_depth); + WRITEL(win->fmt, &dc->win.color_depth); clrsetbits_le32(&dc->win.byte_swap, BYTE_SWAP_MASK, BYTE_SWAP_NOSWAP << BYTE_SWAP_SHIFT); val = win->out_x << H_POSITION_SHIFT; val |= win->out_y << V_POSITION_SHIFT; - writel(val, &dc->win.pos); + WRITEL(val, &dc->win.pos); val = win->out_w << H_SIZE_SHIFT; val |= win->out_h << V_SIZE_SHIFT; - writel(val, &dc->win.size); + WRITEL(val, &dc->win.size); val = (win->w * win->bpp / 8) << H_PRESCALED_SIZE_SHIFT; val |= win->h << V_PRESCALED_SIZE_SHIFT; - writel(val, &dc->win.prescaled_size); + WRITEL(val, &dc->win.prescaled_size); - writel(0, &dc->win.h_initial_dda); - writel(0, &dc->win.v_initial_dda); + WRITEL(0, &dc->win.h_initial_dda); + WRITEL(0, &dc->win.v_initial_dda); h_dda = (win->w * 0x1000) / MAX(win->out_w - 1, 1); v_dda = (win->h * 0x1000) / MAX(win->out_h - 1, 1); val = h_dda << H_DDA_INC_SHIFT; val |= v_dda << V_DDA_INC_SHIFT; - writel(val, &dc->win.dda_increment); + WRITEL(val, &dc->win.dda_increment); - writel(win->stride, &dc->win.line_stride); - writel(0, &dc->win.buf_stride); + WRITEL(win->stride, &dc->win.line_stride); + WRITEL(0, &dc->win.buf_stride); val = WIN_ENABLE; if (win->bpp < 24) val |= COLOR_EXPAND; - writel(val, &dc->win.win_opt); + WRITEL(val, &dc->win.win_opt); - writel((u32) win->phys_addr, &dc->winbuf.start_addr); - writel(win->x, &dc->winbuf.addr_h_offset); - writel(win->y, &dc->winbuf.addr_v_offset); + WRITEL((u32) win->phys_addr, &dc->winbuf.start_addr); + WRITEL(win->x, &dc->winbuf.addr_h_offset); + WRITEL(win->y, &dc->winbuf.addr_v_offset); - writel(0xff00, &dc->win.blend_nokey); - writel(0xff00, &dc->win.blend_1win); + WRITEL(0xff00, &dc->win.blend_nokey); + WRITEL(0xff00, &dc->win.blend_1win); val = GENERAL_ACT_REQ | WIN_A_ACT_REQ; val |= GENERAL_UPDATE | WIN_A_UPDATE; - writel(val, &dc->cmd.state_ctrl); + WRITEL(val, &dc->cmd.state_ctrl); } /* this is really aimed at the lcd panel. That said, there are two display @@ -279,38 +299,72 @@ void display_startup(device_t dev) * light things up here once we're sure it's all working. */ - writel(0x00000100, &dc->cmd.gen_incr_syncpt_ctrl); - writel(0x0000011a, &dc->cmd.cont_syncpt_vsync); - writel(0x00000000, &dc->cmd.int_type); - writel(0x00000000, &dc->cmd.int_polarity); - writel(0x00000000, &dc->cmd.int_mask); - writel(0x00000000, &dc->cmd.int_enb); + /* init dc_a */ + init_dca_regs(); + /* init sor */ + init_sor_regs(); + + /* init dpaux */ + init_dpaux_regs(); + + /* power up perip */ + dp_io_powerup(); + + /* bringup dp */ + dp_bringup(framebuffer_base_mb*MiB); + + { u16 *cp = (void *)(framebuffer_base_mb*MiB); + for(i = 0; i < 1048576*8; i++) + if (i %(2560/2) < 1280/2) + cp[i] = 0x222; + else + cp[i] = 0x888; + } + + /* tell depthcharge ... + */ + struct edid edid; + edid.x_resolution = 2560; + edid.y_resolution = 1700; + edid.bytes_per_line = 2560 * 2; + edid.framebuffer_bits_per_pixel = 16; + set_vbe_mode_info_valid(&edid, (uintptr_t)(framebuffer_base_mb*MiB)); + + if (0){ +/* do we still need these? */ + WRITEL(0x00000100, &dc->cmd.gen_incr_syncpt_ctrl); + WRITEL(0x0000011a, &dc->cmd.cont_syncpt_vsync); + WRITEL(0x00000000, &dc->cmd.int_type); + WRITEL(0x00000000, &dc->cmd.int_polarity); + WRITEL(0x00000000, &dc->cmd.int_mask); + WRITEL(0x00000000, &dc->cmd.int_enb); val = PW0_ENABLE | PW1_ENABLE | PW2_ENABLE; val |= PW3_ENABLE | PW4_ENABLE | PM0_ENABLE; val |= PM1_ENABLE; - writel(val, &dc->cmd.disp_pow_ctrl); + WRITEL(val, &dc->cmd.disp_pow_ctrl); - val = readl(&dc->cmd.disp_cmd); + val = READL(&dc->cmd.disp_cmd); val |= CTRL_MODE_C_DISPLAY << CTRL_MODE_SHIFT; - writel(val, &dc->cmd.disp_cmd); + WRITEL(val, &dc->cmd.disp_cmd); - writel(0x00000020, &dc->disp.mem_high_pri); - writel(0x00000001, &dc->disp.mem_high_pri_timer); + WRITEL(0x00000020, &dc->disp.mem_high_pri); + WRITEL(0x00000001, &dc->disp.mem_high_pri_timer); for (i = 0; i < PIN_REG_COUNT; i++) { - writel(rgb_enb_tab[i], &dc->com.pin_output_enb[i]); - writel(rgb_polarity_tab[i], &dc->com.pin_output_polarity[i]); - writel(rgb_data_tab[i], &dc->com.pin_output_data[i]); + WRITEL(rgb_enb_tab[i], &dc->com.pin_output_enb[i]); + WRITEL(rgb_polarity_tab[i], &dc->com.pin_output_polarity[i]); + WRITEL(rgb_data_tab[i], &dc->com.pin_output_data[i]); } for (i = 0; i < PIN_OUTPUT_SEL_COUNT; i++) - writel(rgb_sel_tab[i], &dc->com.pin_output_sel[i]); + WRITEL(rgb_sel_tab[i], &dc->com.pin_output_sel[i]); if (config->pixel_clock) update_display_mode(&dc->disp, config); if (!setup_window(&window, config)) update_window(dc, &window, config); + } } diff --git a/src/soc/nvidia/tegra124/displayhack.c b/src/soc/nvidia/tegra124/displayhack.c new file mode 100644 index 0000000000..cd6d3dd179 --- /dev/null +++ b/src/soc/nvidia/tegra124/displayhack.c @@ -0,0 +1,1444 @@ +/* this is too ugly to be allowed to live. But it's what works for now. */ +/* + * This file is part of the coreboot project. + * + * Copyright 2013 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "clk_rst.h" +#include +#include "chip.h" +#include "sor.h" +#include +#include +#include +#include +//#include +extern int dump; +unsigned long READL(void *p); +void WRITEL(unsigned long value, void *p); +void debug_dpaux_print(u32 addr, u32 size); +int dpaux_write(u32 addr, u32 size, u32 data); +int dpaux_read(u32 addr, u32 size, u8 * data); + +void init_dca_regs(void) +{ + struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)TEGRA_CLK_RST_BASE; +// u32 val; + + printk(BIOS_SPEW, "JZ: %s: entry\n", __func__); + +#define SWR_DISP1_RST (1 << 27) +#define SWR_HOST1X_RST (1 << 28) +#define CLK_ENB_DISP1 SWR_DISP1_RST +#define CLK_ENB_HOST1X SWR_HOST1X_RST +// REG(CLK_RST_CONTROLLER_RST_DEVICES_L_0, SWR_DISP1_RST, 1); +// REG(CLK_RST_CONTROLLER_RST_DEVICES_L_0, SWR_DISP1_RST, 0); +// REG(CLK_RST_CONTROLLER_CLK_OUT_ENB_L_0, CLK_ENB_DISP1, 1); + /* enable disp1 */ + setbits_le32(&clkrst->rst_dev_l, SWR_DISP1_RST); // Set Reset + clrbits_le32(&clkrst->rst_dev_l, SWR_DISP1_RST); // Clear Reset + setbits_le32(&clkrst->clk_out_enb_l, CLK_ENB_DISP1); // Set Enable + WRITEL(0x00000000, (void *)(0x60006000 + 0x138)); // CLK_SOURCE_DISP1 = PLLP +// WRITEL(0x40000000, (void *)(0x60006000 + 0x138)); // CLK_SOURCE_DISP1 = PLLD + /* enable host1x */ + clrbits_le32(&clkrst->rst_dev_l, SWR_HOST1X_RST); // Clear Reset + setbits_le32(&clkrst->clk_out_enb_l, CLK_ENB_HOST1X); // Set Enable + WRITEL(0x80000000, (void *)(0x60006000 + 0x180)); // CLK_SOURCE_HOST1X = PLLP +// WRITEL(0x40000000, (0x60006000 + 0x180)); // CLK_SOURCE_HOST1X = PLLC + +#if 1 +#define DCA_WRITE(reg, val) \ + { \ + WRITEL(val, (void *)(TEGRA_ARM_DISPLAYA + (reg<<2))); \ + } +#define DCA_READ_M_WRITE(reg, mask, val) \ + { \ + u32 _reg_val; \ + _reg_val = READL( (void *)(TEGRA_ARM_DISPLAYA + (reg<<2))); \ + _reg_val &= ~mask; \ + _reg_val |= val; \ + WRITEL(_reg_val, (void *)(TEGRA_ARM_DISPLAYA + (reg<<2))); \ + } +#else // read back +#define DCA_WRITE(reg, val) \ + { \ + printk(BIOS_SPEW,"DCA_WRITE: addr %#x = %#x\n", + (unsigned int) (TEGRA_ARM_DISPLAYA + (reg<<2)), val); \ + WRITEL(val, (void *)(TEGRA_ARM_DISPLAYA + (reg<<2))); \ + printk(BIOS_SPEW,"reads as %#x\n", \ + (unsigned int)READL( (void *)(TEGRA_ARM_DISPLAYA + (reg<<2)))); \ + } +#endif + + DCA_WRITE(DC_DISP_DISP_CLOCK_CONTROL_0, 0x00000006); //0x542410b8 + DCA_WRITE(DC_CMD_INT_STATUS_0, 0xffffffff); //0x542400dc + DCA_WRITE(DC_CMD_INT_MASK_0, 0x00000000); //0x542400e0 + DCA_WRITE(DC_CMD_INT_ENABLE_0, 0x00800701); //0x542400e4 + DCA_WRITE(DC_CMD_INT_POLARITY_0, 0x00c00706); //0x542400ec + DCA_WRITE(DC_DISP_DISP_SIGNAL_OPTIONS0_0, 0x00000000); //0x54241000 + DCA_WRITE(DC_DISP_DISP_SIGNAL_OPTIONS1_0, 0x00000000); //0x54241004 + DCA_WRITE(DC_DISP_DISP_WIN_OPTIONS_0, 0x00000000); //0x54241008 + DCA_WRITE(DC_DISP_MEM_HIGH_PRIORITY_0, 0x00000000); //0x5424100c + DCA_WRITE(DC_DISP_MEM_HIGH_PRIORITY_TIMER_0, 0x00000000); //0x54241010 + DCA_WRITE(DC_DISP_DISP_TIMING_OPTIONS_0, 0x00000000); //0x54241014 + DCA_WRITE(DC_DISP_REF_TO_SYNC_0, 0x00000000); //0x54241018 + DCA_WRITE(DC_DISP_SYNC_WIDTH_0, 0x00000000); //0x5424101c + DCA_WRITE(DC_DISP_BACK_PORCH_0, 0x00000000); //0x54241020 + DCA_WRITE(DC_DISP_DISP_ACTIVE_0, 0x00030003); //0x54241024 + DCA_WRITE(DC_DISP_FRONT_PORCH_0, 0x00000000); //0x54241028 + DCA_WRITE(DC_DISP_H_PULSE0_CONTROL_0, 0x00000000); //0x5424102c + DCA_WRITE(DC_DISP_H_PULSE0_POSITION_A_0, 0x00000000); //0x54241030 + DCA_WRITE(DC_DISP_H_PULSE0_POSITION_B_0, 0x00000000); //0x54241034 + DCA_WRITE(DC_DISP_H_PULSE0_POSITION_C_0, 0x00000000); //0x54241038 + DCA_WRITE(DC_DISP_H_PULSE0_POSITION_D_0, 0x00000000); //0x5424103c + DCA_WRITE(DC_DISP_H_PULSE1_CONTROL_0, 0x00000000); //0x54241040 + DCA_WRITE(DC_DISP_H_PULSE1_POSITION_A_0, 0x00000000); //0x54241044 + DCA_WRITE(DC_DISP_H_PULSE1_POSITION_B_0, 0x00000000); //0x54241048 + DCA_WRITE(DC_DISP_H_PULSE1_POSITION_C_0, 0x00000000); //0x5424104c + DCA_WRITE(DC_DISP_H_PULSE1_POSITION_D_0, 0x00000000); //0x54241050 + DCA_WRITE(DC_DISP_H_PULSE2_CONTROL_0, 0x00000000); //0x54241054 + DCA_WRITE(DC_DISP_H_PULSE2_POSITION_A_0, 0x00000000); //0x54241058 + DCA_WRITE(DC_DISP_H_PULSE2_POSITION_B_0, 0x00000000); //0x5424105c + DCA_WRITE(DC_DISP_H_PULSE2_POSITION_C_0, 0x00000000); //0x54241060 + DCA_WRITE(DC_DISP_H_PULSE2_POSITION_D_0, 0x00000000); //0x54241064 + DCA_WRITE(DC_DISP_V_PULSE0_CONTROL_0, 0x00000000); //0x54241068 + DCA_WRITE(DC_DISP_V_PULSE0_POSITION_A_0, 0x00000000); //0x5424106c + DCA_WRITE(DC_DISP_V_PULSE0_POSITION_B_0, 0x00000000); //0x54241070 + DCA_WRITE(DC_DISP_V_PULSE0_POSITION_C_0, 0x00000000); //0x54241074 + DCA_WRITE(DC_DISP_V_PULSE1_CONTROL_0, 0x00000000); //0x54241078 + DCA_WRITE(DC_DISP_V_PULSE1_POSITION_A_0, 0x00000000); //0x5424107c + DCA_WRITE(DC_DISP_V_PULSE1_POSITION_B_0, 0x00000000); //0x54241080 + DCA_WRITE(DC_DISP_V_PULSE1_POSITION_C_0, 0x00000000); //0x54241084 + DCA_WRITE(DC_DISP_V_PULSE2_CONTROL_0, 0x00000000); //0x54241088 + DCA_WRITE(DC_DISP_V_PULSE2_POSITION_A_0, 0x00000000); //0x5424108c + DCA_WRITE(DC_DISP_V_PULSE3_CONTROL_0, 0x00000000); //0x54241090 + DCA_WRITE(DC_DISP_V_PULSE3_POSITION_A_0, 0x00000000); //0x54241094 + DCA_WRITE(DC_DISP_M0_CONTROL_0, 0x00000000); //0x54241098 + DCA_WRITE(DC_DISP_M1_CONTROL_0, 0x00000000); //0x5424109c + DCA_WRITE(DC_DISP_DI_CONTROL_0, 0x00000000); //0x542410a0 + DCA_WRITE(DC_DISP_PP_CONTROL_0, 0x00000000); //0x542410a4 + DCA_WRITE(DC_DISP_PP_SELECT_A_0, 0x00000000); //0x542410a8 + DCA_WRITE(DC_DISP_PP_SELECT_B_0, 0x00000000); //0x542410ac + DCA_WRITE(DC_DISP_PP_SELECT_C_0, 0x00000000); //0x542410b0 + DCA_WRITE(DC_DISP_PP_SELECT_D_0, 0x00000000); //0x542410b4 + DCA_WRITE(DC_DISP_DISP_INTERFACE_CONTROL_0, 0x00000000); //0x542410bc + DCA_WRITE(DC_DISP_DISP_COLOR_CONTROL_0, 0x00000000); //0x542410c0 + DCA_WRITE(DC_DISP_SHIFT_CLOCK_OPTIONS_0, 0x00000000); //0x542410c4 + DCA_WRITE(DC_DISP_DATA_ENABLE_OPTIONS_0, 0x00000000); //0x542410c8 + DCA_WRITE(DC_DISP_SERIAL_INTERFACE_OPTIONS_0, 0x00000000); //0x542410cc + DCA_WRITE(DC_DISP_LCD_SPI_OPTIONS_0, 0x00000000); //0x542410d0 + DCA_WRITE(DC_DISP_COLOR_KEY0_LOWER_0, 0x00000000); //0x542410d8 + DCA_WRITE(DC_DISP_COLOR_KEY0_UPPER_0, 0x00000000); //0x542410dc + DCA_WRITE(DC_DISP_COLOR_KEY1_LOWER_0, 0x00000000); //0x542410e0 + DCA_WRITE(DC_DISP_COLOR_KEY1_UPPER_0, 0x00000000); //0x542410e4 + DCA_WRITE(DC_DISP_CURSOR_FOREGROUND_0, 0x00000000); //0x542410f0 + DCA_WRITE(DC_DISP_CURSOR_BACKGROUND_0, 0x00000000); //0x542410f4 + DCA_WRITE(DC_DISP_CURSOR_START_ADDR_0, 0x00200000); //0x542410f8 + DCA_WRITE(DC_DISP_CURSOR_START_ADDR_NS_0, 0x00000000); //0x542410fc + DCA_WRITE(DC_DISP_CURSOR_POSITION_0, 0x00000000); //0x54241100 + DCA_WRITE(DC_DISP_CURSOR_POSITION_NS_0, 0x00000000); //0x54241104 + DCA_WRITE(DC_DISP_INIT_SEQ_CONTROL_0, 0x00000000); //0x54241108 + DCA_WRITE(DC_DISP_SPI_INIT_SEQ_DATA_A_0, 0x00000000); //0x5424110c + DCA_WRITE(DC_DISP_SPI_INIT_SEQ_DATA_B_0, 0x00000000); //0x54241110 + DCA_WRITE(DC_DISP_SPI_INIT_SEQ_DATA_C_0, 0x00000000); //0x54241114 + DCA_WRITE(DC_DISP_SPI_INIT_SEQ_DATA_D_0, 0x00000000); //0x54241118 + DCA_WRITE(DC_DISP_DC_MCCIF_FIFOCTRL_0, 0x00000000); //0x54241200 + DCA_WRITE(DC_DISP_MCCIF_DISPLAY0A_HYST_0, 0xcf401f1f); //0x54241204 + DCA_WRITE(DC_DISP_MCCIF_DISPLAY0B_HYST_0, 0xcf401f1f); //0x54241208 + DCA_WRITE(DC_DISP_MCCIF_DISPLAY0C_HYST_0, 0xcf401f1f); //0x5424120c + DCA_WRITE(DC_DISP_DISP_MISC_CONTROL_0, 0x00000002); //0x54241304 + DCA_WRITE(DC_DISP_SD_CONTROL_0, 0x00004000); //0x54241308 + DCA_WRITE(DC_DISP_SD_CSC_COEFF_0, 0x00000000); //0x5424130c + + DCA_WRITE(DC_DISP_SD_LUT_0, 0x00000000); //0x54241310 +#define DC_DISP_SD_LUT_1_0 0x4c5 +#define DC_DISP_SD_LUT_2_0 0x4c6 +#define DC_DISP_SD_LUT_3_0 0x4c7 +#define DC_DISP_SD_LUT_4_0 0x4c8 +#define DC_DISP_SD_LUT_5_0 0x4c9 +#define DC_DISP_SD_LUT_6_0 0x4ca +#define DC_DISP_SD_LUT_7_0 0x4cb +#define DC_DISP_SD_LUT_8_0 0x4cc + DCA_WRITE(DC_DISP_SD_LUT_1_0, 0x00000000); //0x54241314 + DCA_WRITE(DC_DISP_SD_LUT_2_0, 0x00000000); //0x54241318 + DCA_WRITE(DC_DISP_SD_LUT_3_0, 0x00000000); //0x5424131c + DCA_WRITE(DC_DISP_SD_LUT_4_0, 0x00000000); //0x54241320 + DCA_WRITE(DC_DISP_SD_LUT_5_0, 0x00000000); //0x54241324 + DCA_WRITE(DC_DISP_SD_LUT_6_0, 0x00000000); //0x54241328 + DCA_WRITE(DC_DISP_SD_LUT_7_0, 0x00000000); //0x5424132c + DCA_WRITE(DC_DISP_SD_LUT_8_0, 0x00000000); //0x54241330 + DCA_WRITE(DC_DISP_SD_FLICKER_CONTROL_0, 0x00000000); //0x54241334 + DCA_WRITE(DC_DISP_SD_PIXEL_COUNT_0, 0x00000000); //0x54241338 + + DCA_WRITE(DC_DISP_SD_HISTOGRAM_0, 0x00000000); //0x5424133c +#define DC_DISP_SD_HISTOGRAM_1_0 0x4d0 +#define DC_DISP_SD_HISTOGRAM_2_0 0x4d1 +#define DC_DISP_SD_HISTOGRAM_3_0 0x4d2 +#define DC_DISP_SD_HISTOGRAM_4_0 0x4d3 +#define DC_DISP_SD_HISTOGRAM_5_0 0x4d4 +#define DC_DISP_SD_HISTOGRAM_6_0 0x4d5 +#define DC_DISP_SD_HISTOGRAM_7_0 0x4d6 + DCA_WRITE(DC_DISP_SD_HISTOGRAM_1_0, 0x00000000); //0x54241340 + DCA_WRITE(DC_DISP_SD_HISTOGRAM_2_0, 0x00000000); //0x54241344 + DCA_WRITE(DC_DISP_SD_HISTOGRAM_3_0, 0x00000000); //0x54241348 + DCA_WRITE(DC_DISP_SD_HISTOGRAM_4_0, 0x00000000); //0x5424134c + DCA_WRITE(DC_DISP_SD_HISTOGRAM_5_0, 0x00000000); //0x54241350 + DCA_WRITE(DC_DISP_SD_HISTOGRAM_6_0, 0x00000000); //0x54241354 + DCA_WRITE(DC_DISP_SD_HISTOGRAM_7_0, 0x00000000); //0x54241358 + DCA_WRITE(DC_DISP_SD_BL_PARAMETERS_0, 0x00000400); //0x5424135c + DCA_WRITE(DC_DISP_SD_BL_TF_0, 0x00000000); //0x54241360 +#define DC_DISP_SD_BL_TF_1_0 0x4d9 +#define DC_DISP_SD_BL_TF_2_0 0x4da +#define DC_DISP_SD_BL_TF_3_0 0x4db + DCA_WRITE(DC_DISP_SD_BL_TF_1_0, 0x00000000); //0x54241364 + DCA_WRITE(DC_DISP_SD_BL_TF_2_0, 0x00000000); //0x54241368 + DCA_WRITE(DC_DISP_SD_BL_TF_3_0, 0x00000000); //0x5424136c + DCA_WRITE(DC_DISP_SD_BL_CONTROL_0, 0x00000000); //0x54241370 + DCA_WRITE(DC_DISP_SD_HW_K_VALUES_0, 0x00000000); //0x54241374 + DCA_WRITE(DC_DISP_SD_MAN_K_VALUES_0, 0x00000000); //0x54241378 + DCA_WRITE(DC_DISP_SD_K_LIMIT_0, 0x00000000); //0x5424137c + DCA_WRITE(DC_DISP_SD_WINDOW_POSITION_0, 0x00000000); //0x54241380 + DCA_WRITE(DC_DISP_SD_WINDOW_SIZE_0, 0x00000000); //0x54241384 + DCA_WRITE(DC_DISP_SD_SOFT_CLIPPING_0, 0x02000080); //0x54241388 + DCA_WRITE(DC_DISP_SD_SMOOTH_K_0, 0x00000000); //0x5424138c + DCA_WRITE(DC_DISP_BLEND_BACKGROUND_COLOR_0, 0x00000000); //0x54241390 + DCA_WRITE(DC_DISP_INTERLACE_CONTROL_0, 0x00000000); //0x54241394 + DCA_WRITE(DC_DISP_INTERLACE_FIELD2_REF_TO_SYNC_0, 0x00000000); //0x54241398 + DCA_WRITE(DC_DISP_INTERLACE_FIELD2_SYNC_WIDTH_0, 0x00000000); //0x5424139c + DCA_WRITE(DC_DISP_INTERLACE_FIELD2_BACK_PORCH_0, 0x00000000); //0x542413a0 + DCA_WRITE(DC_DISP_INTERLACE_FIELD2_FRONT_PORCH_0, 0x00000000); //0x542413a4 + DCA_WRITE(DC_DISP_INTERLACE_FIELD2_DISP_ACTIVE_0, 0x00000000); //0x542413a8 + DCA_WRITE(DC_DISP_CURSOR_UNDERFLOW_CTRL_0, 0x00000000); //0x542413ac + DCA_WRITE(DC_DISP_CURSOR_START_ADDR_HI_0, 0x00000000); //0x542413b0 + DCA_WRITE(DC_DISP_CURSOR_START_ADDR_HI_NS_0, 0x00000000); //0x542413b4 + DCA_WRITE(DC_DISP_CURSOR_INTERLACE_CONTROL_0, 0x00000000); //0x542413b8 + DCA_WRITE(DC_DISP_CSC2_CONTROL_0, 0x00000000); //0x542413bc + DCA_WRITE(DC_DISP_BLEND_CURSOR_CONTROL_0, 0x00000000); //0x542413c4 + DCA_WRITE(DC_DISP_DVFS_CURSOR_CONTROL_0, 0x00000003); //0x542413c8 + DCA_WRITE(DC_DISP_CURSOR_UFLOW_DBG_PIXEL_0, 0x00000000); //0x542413cc + DCA_WRITE(DC_DISP_CURSOR_SPOOLUP_CONTROL_0, 0x00000001); //0x542413d0 + DCA_WRITE(DC_DISP_DISPLAY_CLK_GATE_OVERRIDE_0, 0x00000000); //0x542413d4 + DCA_WRITE(DC_DISP_DISPLAY_DBG_TIMING_0, 0x00000000); //0x542413d8 + DCA_WRITE(DC_DISP_DISPLAY_SPARE0_0, 0x00000000); //0x542413dc + DCA_WRITE(DC_DISP_DISPLAY_SPARE1_0, 0x00000000); //0x542413e0 + +#define wr32(reg, val) \ + WRITEL(val, (void *)reg) + + wr32((TEGRA_ARM_DISPLAYA + 0x0200), 0x00000000); + wr32((TEGRA_ARM_DISPLAYA + 0x0400), 0x00000000); + + DCA_WRITE(DC_CMD_DISPLAY_WINDOW_HEADER_0, 0x000000F0); + DCA_WRITE(DC_WIN_A_WIN_OPTIONS_0, 0x00000000); + DCA_WRITE(DC_WIN_A_BYTE_SWAP_0, 0x00000000); + DCA_WRITE(DC_WIN_A_BUFFER_CONTROL_0, 0x00000000); + DCA_WRITE(DC_WIN_A_COLOR_DEPTH_0, 0x0000000C); + DCA_WRITE(DC_WIN_A_POSITION_0, 0x00000000); + DCA_WRITE(DC_WIN_A_SIZE_0, 0x00000000); + DCA_WRITE(DC_WIN_A_PRESCALED_SIZE_0, 0x00000000); + DCA_WRITE(DC_WIN_A_H_INITIAL_DDA_0, 0x00000000); + DCA_WRITE(DC_WIN_A_V_INITIAL_DDA_0, 0x00000000); + DCA_WRITE(DC_WIN_A_DDA_INCREMENT_0, 0x00000000); + DCA_WRITE(DC_WIN_A_LINE_STRIDE_0, 0x00000000); + DCA_WRITE(DC_WIN_A_DV_CONTROL_0, 0x00000000); + + DCA_WRITE(DC_WIN_A_BLEND_LAYER_CONTROL_0, 0x01000000); + DCA_WRITE(DC_WIN_A_BLEND_MATCH_SELECT_0, 0x00000000); + DCA_WRITE(DC_WIN_A_BLEND_NOMATCH_SELECT_0, 0x00000000); + DCA_WRITE(DC_WIN_A_BLEND_ALPHA_1BIT_0, 0x00000000); + DCA_WRITE(DC_WINC_A_PALETTE_COLOR_EXT_0, 0x00000000); + DCA_WRITE(DC_WINC_A_CSC_YOF_0, 0x00000000); + DCA_WRITE(DC_WINC_A_CSC_KYRGB_0, 0x00000000); + DCA_WRITE(DC_WINC_A_CSC_KUR_0, 0x00000000); + DCA_WRITE(DC_WINC_A_CSC_KVR_0, 0x00000000); + DCA_WRITE(DC_WINC_A_CSC_KUG_0, 0x00000000); + DCA_WRITE(DC_WINC_A_CSC_KVG_0, 0x00000000); + DCA_WRITE(DC_WINC_A_CSC_KUB_0, 0x00000000); + DCA_WRITE(DC_WINC_A_CSC_KVB_0, 0x00000000); + DCA_WRITE(DC_WINBUF_A_START_ADDR_HI_0, 0x00000000); + DCA_WRITE(DC_WINBUF_A_ADDR_H_OFFSET_0, 0x00000000); + DCA_WRITE(DC_WINBUF_A_ADDR_V_OFFSET_0, 0x00000000); + DCA_WRITE(DC_CMD_DISPLAY_WINDOW_HEADER_0, 0x00000000); + + DCA_WRITE(DC_COM_CRC_CONTROL_0, 0x00000000); //0x54240c00 + DCA_WRITE(DC_COM_CRC_CHECKSUM_0, 0x00000000); //0x54240c04 + DCA_WRITE(DC_COM_PIN_OUTPUT_ENABLE0_0, 0x00000000); //0x54240c08 + DCA_WRITE(DC_COM_PIN_OUTPUT_ENABLE1_0, 0x00000000); //0x54240c0c + DCA_WRITE(DC_COM_PIN_OUTPUT_ENABLE2_0, 0x00510104); //0x54240c10 + DCA_WRITE(DC_COM_PIN_OUTPUT_ENABLE3_0, 0x00000555); //0x54240c14 + DCA_WRITE(DC_COM_PIN_OUTPUT_POLARITY0_0, 0x00000000); //0x54240c18 + DCA_WRITE(DC_COM_PIN_OUTPUT_POLARITY1_0, 0x00000000); //0x54240c1c + DCA_WRITE(DC_COM_PIN_OUTPUT_POLARITY2_0, 0x00000000); //0x54240c20 + DCA_WRITE(DC_COM_PIN_OUTPUT_POLARITY3_0, 0x00000000); //0x54240c24 + DCA_WRITE(DC_COM_PIN_OUTPUT_DATA0_0, 0x00000000); //0x54240c28 + DCA_WRITE(DC_COM_PIN_OUTPUT_DATA1_0, 0x00000000); //0x54240c2c + DCA_WRITE(DC_COM_PIN_OUTPUT_DATA2_0, 0x00000000); //0x54240c30 + DCA_WRITE(DC_COM_PIN_OUTPUT_DATA3_0, 0x00000000); //0x54240c34 + DCA_WRITE(DC_COM_PIN_INPUT_DATA0_0, 0x00000000); //0x54240c48 + DCA_WRITE(DC_COM_PIN_INPUT_DATA1_0, 0x00000000); //0x54240c4c + DCA_WRITE(DC_COM_PIN_OUTPUT_SELECT0_0, 0x00000000); //0x54240c50 + DCA_WRITE(DC_COM_PIN_OUTPUT_SELECT1_0, 0x00000000); //0x54240c54 + DCA_WRITE(DC_COM_PIN_OUTPUT_SELECT2_0, 0x00000000); //0x54240c58 + DCA_WRITE(DC_COM_PIN_OUTPUT_SELECT3_0, 0x00000000); //0x54240c5c + DCA_WRITE(DC_COM_PIN_OUTPUT_SELECT4_0, 0x00000000); //0x54240c60 + DCA_WRITE(DC_COM_PIN_OUTPUT_SELECT5_0, 0x00000000); //0x54240c64 + DCA_WRITE(DC_COM_PIN_OUTPUT_SELECT6_0, 0x00000000); //0x54240c68 + DCA_WRITE(DC_COM_PIN_MISC_CONTROL_0, 0x00000000); //0x54240c6c + DCA_WRITE(DC_COM_PM0_CONTROL_0, 0x00000000); //0x54240c70 + DCA_WRITE(DC_COM_PM0_DUTY_CYCLE_0, 0x00000000); //0x54240c74 + DCA_WRITE(DC_COM_PM1_CONTROL_0, 0x00000000); //0x54240c78 + DCA_WRITE(DC_COM_PM1_DUTY_CYCLE_0, 0x00000000); //0x54240c7c + DCA_WRITE(DC_COM_SPI_CONTROL_0, 0x00000000); //0x54240c80 + DCA_WRITE(DC_COM_SPI_START_BYTE_0, 0x00000000); //0x54240c84 + DCA_WRITE(DC_COM_HSPI_WRITE_DATA_AB_0, 0x00000000); //0x54240c88 + DCA_WRITE(DC_COM_HSPI_WRITE_DATA_CD_0, 0x00000000); //0x54240c8c + DCA_WRITE(DC_COM_HSPI_CS_DC_0, 0x00000000); //0x54240c90 + DCA_WRITE(DC_COM_SCRATCH_REGISTER_A_0, 0x00000000); //0x54240c94 + DCA_WRITE(DC_COM_SCRATCH_REGISTER_B_0, 0x00000000); //0x54240c98 + DCA_WRITE(DC_COM_CRC_CHECKSUM_LATCHED_0, 0x00000000); //0x54240ca4 + DCA_WRITE(DC_COM_CMU_CSC_KRR_0, 0x00000000); //0x54240ca8 + DCA_WRITE(DC_COM_CMU_CSC_KGR_0, 0x00000000); //0x54240cac + DCA_WRITE(DC_COM_CMU_CSC_KBR_0, 0x00000000); //0x54240cb0 + DCA_WRITE(DC_COM_CMU_CSC_KRG_0, 0x00000000); //0x54240cb4 + DCA_WRITE(DC_COM_CMU_CSC_KGG_0, 0x00000000); //0x54240cb8 + DCA_WRITE(DC_COM_CMU_CSC_KBG_0, 0x00000000); //0x54240cbc + DCA_WRITE(DC_COM_CMU_CSC_KRB_0, 0x00000000); //0x54240cc0 + DCA_WRITE(DC_COM_CMU_CSC_KGB_0, 0x00000000); //0x54240cc4 + DCA_WRITE(DC_COM_CMU_CSC_KBB_0, 0x00000000); //0x54240cc8 + DCA_WRITE(DC_COM_CMU_LUT_MASK_0, 0x00000000); //0x54240ccc + DCA_WRITE(DC_COM_CMU_LUT1_0, 0x00000000); //0x54240cd8 + DCA_WRITE(DC_COM_CMU_LUT2_0, 0x00000000); //0x54240cdc + DCA_WRITE(DC_COM_CMU_LUT1_READ_0, 0x00000000); //0x54240ce0 + DCA_WRITE(DC_COM_CMU_LUT2_READ_0, 0x00000000); //0x54240ce4 + DCA_WRITE(DC_CMD_GENERAL_INCR_SYNCPT_CNTRL_0, 0x00000000); //0x54240004 + DCA_WRITE(DC_CMD_GENERAL_INCR_SYNCPT_ERROR_0, 0x00000000); //0x54240008 + DCA_WRITE(DC_CMD_WIN_A_INCR_SYNCPT_CNTRL_0, 0x00000000); //0x54240024 + DCA_WRITE(DC_CMD_WIN_A_INCR_SYNCPT_ERROR_0, 0x00000000); //0x54240028 + DCA_WRITE(DC_CMD_WIN_B_INCR_SYNCPT_CNTRL_0, 0x00000000); //0x54240044 + DCA_WRITE(DC_CMD_WIN_B_INCR_SYNCPT_ERROR_0, 0x00000000); //0x54240048 + DCA_WRITE(DC_CMD_WIN_C_INCR_SYNCPT_CNTRL_0, 0x00000000); //0x54240064 + DCA_WRITE(DC_CMD_WIN_C_INCR_SYNCPT_ERROR_0, 0x00000000); //0x54240068 + DCA_WRITE(DC_CMD_CONT_SYNCPT_VSYNC_0, 0x00000000); //0x542400a0 + DCA_WRITE(DC_CMD_DISPLAY_COMMAND_OPTION0_0, 0x00000000); //0x542400c4 + DCA_WRITE(DC_CMD_DISPLAY_COMMAND_0, 0x00000000); //0x542400c8 + DCA_WRITE(DC_CMD_SIGNAL_RAISE_0, 0x00000000); //0x542400cc + DCA_WRITE(DC_CMD_DISPLAY_POWER_CONTROL_0, 0x00000000); //0x542400d8 + DCA_WRITE(DC_CMD_SIGNAL_RAISE1_0, 0x00000000); //0x542400f0 + DCA_WRITE(DC_CMD_SIGNAL_RAISE2_0, 0x00000000); //0x542400f4 + DCA_WRITE(DC_CMD_SIGNAL_RAISE3_0, 0x00000000); //0x542400f8 + DCA_WRITE(DC_CMD_STATE_CONTROL_0, 0x00000000); //0x54240104 + DCA_WRITE(DC_CMD_DISPLAY_WINDOW_HEADER_0, 0x00000000); //0x54240108 + DCA_WRITE(DC_CMD_REG_ACT_CONTROL_0, 0x00000000); //0x5424010c + DCA_WRITE(DC_CMD_WIN_T_STATE_CONTROL_0, 0x00000000); //0x54240110 + DCA_WRITE(DC_CMD_SECURE_CONTROL_0, 0x00000000); //0x54240114 + DCA_WRITE(DC_CMD_WIN_D_INCR_SYNCPT_CNTRL_0, 0x00000000); //0x54240134 + DCA_WRITE(DC_CMD_WIN_D_INCR_SYNCPT_ERROR_0, 0x00000000); //0x54240138 + printk(BIOS_SPEW, "initial DCA done\n"); +} + +void init_sor_regs(void) +{ + struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)TEGRA_CLK_RST_BASE; + + printk(BIOS_SPEW, "JZ: %s: entry\n", __func__); + +#define SWR_SOR0_RST (1 << 22) +#define CLK_ENB_SOR0 SWR_SOR0_RST +// REG(CLK_RST_CONTROLLER_RST_DEVICES_X_0, SWR_SOR0_RST, 1) +// REG(CLK_RST_CONTROLLER_RST_DEVICES_X_0, SWR_SOR0_RST, 0) +// REG(CLK_RST_CONTROLLER_CLK_OUT_ENB_X_0, CLK_ENB_SOR0, 1) +// REG(CLK_RST_CONTROLLER_CLK_SOURCE_SOR0_0, 0) //0x60006414 + setbits_le32(&clkrst->rst_devices_x, SWR_SOR0_RST); // Set Reset + clrbits_le32(&clkrst->rst_devices_x, SWR_SOR0_RST); // Clear Reset + setbits_le32(&clkrst->clk_out_enb_x, CLK_ENB_SOR0); // Set Enable + WRITEL(0x0, (void *)(0x60006000 + 0x414)); // CLK_SOURCE_SOR0 = PLLP + + //WRITEL(0xc000c000, (0x60006000 + 0x414)); // CLK_SOURCE_SOR0 = CLK_M +#if 0 + u32 reg_val; + reg_val = READL((void *)(0x60006000 + 0x414)); + reg_val &= ~(0x7 << 29); + reg_val |= (0x4 << 29); // PLLC + WRITEL(reg_val, (void *)(0x60006000 + 0x414)); // CLK_SOURCE_SOR0 = PLLC +#endif + +#if 1 +#define SOR_WRITE(reg, val) \ + { \ + WRITEL(val, (void *)(TEGRA_ARM_SOR + (reg<<2))); \ + } + +#define SOR_READ(reg) READL( (void *)(TEGRA_ARM_SOR + (reg<<2))) + +#else // read back +#define SOR_WRITE(reg, val) \ + { \ + printk(BIOS_SPEW,"SOR_WRITE: addr %#x = %#x\n", + (unsigned int) (TEGRA_ARM_SOR + (reg<<2)), val); \ + WRITEL(val, (void *)(TEGRA_ARM_SOR + (reg<<2))); \ + printk(BIOS_SPEW,"= %#x\n", \ + (unsigned int)READL( (void *)(TEGRA_ARM_SOR + (reg<<2)))); \ + } +#endif +#define SOR_READ_M_WRITE(reg, mask, val) \ + { \ + u32 _reg_val; \ + _reg_val = READL( (void *)(TEGRA_ARM_SOR + (reg<<2))); \ + _reg_val &= ~mask; \ + _reg_val |= val; \ + WRITEL(_reg_val, (void *)(TEGRA_ARM_SOR + (reg<<2))); \ + } + + SOR_WRITE(SOR_NV_PDISP_SOR_SUPER_STATE0_0, 0x00000000); //0x54540004 + SOR_WRITE(SOR_NV_PDISP_SOR_SUPER_STATE1_0, 0x00000000); //0x54540008 + SOR_WRITE(SOR_NV_PDISP_SOR_STATE0_0, 0x00000000); //0x5454000c + SOR_WRITE(SOR_NV_PDISP_SOR_STATE1_0, 0x00000040); //0x54540010 + SOR_WRITE(SOR_NV_PDISP_HEAD_STATE0, 0x00000000); //0x54540014 + SOR_WRITE(SOR_NV_PDISP_HEAD_STATE0_1, 0x00000000); //0x54540018 + SOR_WRITE(SOR_NV_PDISP_HEAD_STATE1, 0x01011000); //0x5454001c + SOR_WRITE(SOR_NV_PDISP_HEAD_STATE1_1, 0x01011000); //0x54540020 + SOR_WRITE(SOR_NV_PDISP_HEAD_STATE2, 0x00000001); //0x54540024 + SOR_WRITE(SOR_NV_PDISP_HEAD_STATE2_1, 0x00000001); //0x54540028 + SOR_WRITE(SOR_NV_PDISP_HEAD_STATE3, 0x00010011); //0x5454002c + SOR_WRITE(SOR_NV_PDISP_HEAD_STATE3_1, 0x00010011); //0x54540030 + SOR_WRITE(SOR_NV_PDISP_HEAD_STATE4, 0x00110100); //0x54540034 + SOR_WRITE(SOR_NV_PDISP_HEAD_STATE4_1, 0x00110100); //0x54540038 + SOR_WRITE(SOR_NV_PDISP_HEAD_STATE5, 0x00000001); //0x5454003c + SOR_WRITE(SOR_NV_PDISP_HEAD_STATE5_1, 0x00000001); //0x54540040 + SOR_WRITE(SOR_NV_PDISP_SOR_CRC_CNTRL_0, 0x00000000); //0x54540044 + SOR_WRITE(SOR_NV_PDISP_SOR_DP_DEBUG_MVID_0, 0x00000000); //0x54540048 + SOR_WRITE(SOR_NV_PDISP_SOR_CLK_CNTRL_0, 0x00000018); //0x5454004c + SOR_WRITE(SOR_NV_PDISP_SOR_CAP_0, 0x00000000); //0x54540050 + SOR_WRITE(SOR_NV_PDISP_SOR_PWR_0, 0x00000000); //0x54540054 + SOR_WRITE(SOR_NV_PDISP_SOR_TEST_0, 0x00800000); //0x54540058 + SOR_WRITE(SOR_NV_PDISP_SOR_PLL0_0, 0x0f0003d5); //0x5454005c + SOR_WRITE(SOR_NV_PDISP_SOR_PLL1_0, 0x00001000); //0x54540060 + SOR_WRITE(SOR_NV_PDISP_SOR_PLL2_0, 0x01c00000); //0x54540064 + SOR_WRITE(SOR_NV_PDISP_SOR_PLL3_0, 0x38002220); //0x54540068 + SOR_WRITE(SOR_NV_PDISP_SOR_CSTM_0, 0x0001c800); //0x5454006c + SOR_WRITE(SOR_NV_PDISP_SOR_LVDS_0, 0x0001c800); //0x54540070 + SOR_WRITE(SOR_NV_PDISP_SOR_CRCA_0, 0x00000000); //0x54540074 + SOR_WRITE(SOR_NV_PDISP_SOR_CRCB_0, 0x00000000); //0x54540078 + SOR_WRITE(SOR_NV_PDISP_SOR_BLANK_0, 0x00000000); //0x5454007c + SOR_WRITE(SOR_NV_PDISP_SOR_SEQ_CTL_0, 0x00008800); //0x54540080 + SOR_WRITE(SOR_NV_PDISP_SOR_LANE_SEQ_CTL_0, 0x00011000); //0x54540084 + SOR_WRITE(SOR_NV_PDISP_SOR_SEQ_INST0_0, 0x01008000); //0x54540088 + SOR_WRITE(SOR_NV_PDISP_SOR_SEQ_INST1_0, 0x01008000); //0x5454008c + SOR_WRITE(SOR_NV_PDISP_SOR_SEQ_INST2_0, 0x01008000); //0x54540090 + SOR_WRITE(SOR_NV_PDISP_SOR_SEQ_INST3_0, 0x01008000); //0x54540094 + SOR_WRITE(SOR_NV_PDISP_SOR_SEQ_INST4_0, 0x01008000); //0x54540098 + SOR_WRITE(SOR_NV_PDISP_SOR_SEQ_INST5_0, 0x01008000); //0x5454009c + SOR_WRITE(SOR_NV_PDISP_SOR_SEQ_INST6_0, 0x01008000); //0x545400a0 + SOR_WRITE(SOR_NV_PDISP_SOR_SEQ_INST7_0, 0x01008000); //0x545400a4 + SOR_WRITE(SOR_NV_PDISP_SOR_SEQ_INST8_0, 0x01008000); //0x545400a8 + SOR_WRITE(SOR_NV_PDISP_SOR_SEQ_INST9_0, 0x01008000); //0x545400ac + SOR_WRITE(SOR_NV_PDISP_SOR_SEQ_INSTA_0, 0x01008000); //0x545400b0 + SOR_WRITE(SOR_NV_PDISP_SOR_SEQ_INSTB_0, 0x01008000); //0x545400b4 + SOR_WRITE(SOR_NV_PDISP_SOR_SEQ_INSTC_0, 0x01008000); //0x545400b8 + SOR_WRITE(SOR_NV_PDISP_SOR_SEQ_INSTD_0, 0x01008000); //0x545400bc + SOR_WRITE(SOR_NV_PDISP_SOR_SEQ_INSTE_0, 0x01008000); //0x545400c0 + SOR_WRITE(SOR_NV_PDISP_SOR_SEQ_INSTF_0, 0x01008000); //0x545400c4 + SOR_WRITE(SOR_NV_PDISP_SOR_PWM_DIV_0, 0x00000000); //0x545400c8 + SOR_WRITE(SOR_NV_PDISP_SOR_PWM_CTL_0, 0x00000000); //0x545400cc + SOR_WRITE(SOR_NV_PDISP_SOR_VCRCA0_0, 0x00000000); //0x545400d0 + SOR_WRITE(SOR_NV_PDISP_SOR_VCRCA1_0, 0x00000000); //0x545400d4 + SOR_WRITE(SOR_NV_PDISP_SOR_VCRCB0_0, 0x00000000); //0x545400d8 + SOR_WRITE(SOR_NV_PDISP_SOR_VCRCB1_0, 0x00000000); //0x545400dc + SOR_WRITE(SOR_NV_PDISP_SOR_CCRCA0_0, 0x00000000); //0x545400e0 + SOR_WRITE(SOR_NV_PDISP_SOR_CCRCA1_0, 0x00000000); //0x545400e4 + SOR_WRITE(SOR_NV_PDISP_SOR_CCRCB0_0, 0x00000000); //0x545400e8 + SOR_WRITE(SOR_NV_PDISP_SOR_CCRCB1_0, 0x00000000); //0x545400ec + SOR_WRITE(SOR_NV_PDISP_SOR_EDATAA0_0, 0x00000000); //0x545400f0 + SOR_WRITE(SOR_NV_PDISP_SOR_EDATAA1_0, 0x00000000); //0x545400f4 + SOR_WRITE(SOR_NV_PDISP_SOR_EDATAB0_0, 0x00000000); //0x545400f8 + SOR_WRITE(SOR_NV_PDISP_SOR_EDATAB1_0, 0x00000000); //0x545400fc + SOR_WRITE(SOR_NV_PDISP_SOR_COUNTA0_0, 0x00000000); //0x54540100 + SOR_WRITE(SOR_NV_PDISP_SOR_COUNTA1_0, 0x00000000); //0x54540104 + SOR_WRITE(SOR_NV_PDISP_SOR_COUNTB0_0, 0x00000000); //0x54540108 + SOR_WRITE(SOR_NV_PDISP_SOR_COUNTB1_0, 0x00000000); //0x5454010c + SOR_WRITE(SOR_NV_PDISP_SOR_DEBUGA0_0, 0x00000000); //0x54540110 + SOR_WRITE(SOR_NV_PDISP_SOR_DEBUGA1_0, 0x00000000); //0x54540114 + SOR_WRITE(SOR_NV_PDISP_SOR_DEBUGB0_0, 0x00000000); //0x54540118 + SOR_WRITE(SOR_NV_PDISP_SOR_DEBUGB1_0, 0x00000000); //0x5454011c + SOR_WRITE(SOR_NV_PDISP_SOR_TRIG_0, 0x00000000); //0x54540120 + SOR_WRITE(SOR_NV_PDISP_SOR_MSCHECK_0, 0x80000000); //0x54540124 + SOR_WRITE(SOR_NV_PDISP_SOR_XBAR_CTRL_0, 0x8d111a23); //0x54540128 + SOR_WRITE(SOR_NV_PDISP_SOR_XBAR_POL_0, 0x00000000); //0x5454012c + SOR_WRITE(SOR_NV_PDISP_SOR_DP_LINKCTL0_0, 0x00000100); //0x54540130 + SOR_WRITE(SOR_NV_PDISP_SOR_DP_LINKCTL1_0, 0x00000100); //0x54540134 + SOR_WRITE(SOR_NV_PDISP_SOR_LANE_DRIVE_CURRENT0_0, 0x40404040); //0x54540138 + SOR_WRITE(SOR_NV_PDISP_SOR_LANE_DRIVE_CURRENT1_0, 0x80808080); //0x5454013c + SOR_WRITE(SOR_NV_PDISP_SOR_LANE4_DRIVE_CURRENT0_0, 0x00000040); //0x54540140 + SOR_WRITE(SOR_NV_PDISP_SOR_LANE4_DRIVE_CURRENT1_0, 0x00000080); //0x54540144 + SOR_WRITE(SOR_NV_PDISP_SOR_LANE_PREEMPHASIS0_0, 0x00000000); //0x54540148 + SOR_WRITE(SOR_NV_PDISP_SOR_LANE_PREEMPHASIS1_0, 0x00000000); //0x5454014c + SOR_WRITE(SOR_NV_PDISP_SOR_LANE4_PREEMPHASIS0_0, 0x00000000); //0x54540150 + SOR_WRITE(SOR_NV_PDISP_SOR_LANE4_PREEMPHASIS1_0, 0x00000000); //0x54540154 + SOR_WRITE(SOR_NV_PDISP_SOR_POSTCURSOR0_0, 0x00000000); //0x54540158 + SOR_WRITE(SOR_NV_PDISP_SOR_POSTCURSOR1_0, 0x00000000); //0x5454015c + SOR_WRITE(SOR_NV_PDISP_SOR_DP_CONFIG0_0, 0x94000000); //0x54540160 + SOR_WRITE(SOR_NV_PDISP_SOR_DP_CONFIG1_0, 0x94000000); //0x54540164 + SOR_WRITE(SOR_NV_PDISP_SOR_DP_MN0_0, 0x00008000); //0x54540168 + SOR_WRITE(SOR_NV_PDISP_SOR_DP_MN1_0, 0x00008000); //0x5454016c + SOR_WRITE(SOR_NV_PDISP_SOR_DP_PADCTL0_0, 0x00800000); //0x54540170 + SOR_WRITE(SOR_NV_PDISP_SOR_DP_PADCTL1_0, 0x00000000); //0x54540174 + SOR_WRITE(SOR_NV_PDISP_SOR_DP_DEBUG0_0, 0x00000000); //0x54540178 + SOR_WRITE(SOR_NV_PDISP_SOR_DP_DEBUG1_0, 0x00000000); //0x5454017c + SOR_WRITE(SOR_NV_PDISP_SOR_DP_SPARE0_0, 0x00000002); //0x54540180 + SOR_WRITE(SOR_NV_PDISP_SOR_DP_SPARE1_0, 0x00000000); //0x54540184 + SOR_WRITE(SOR_NV_PDISP_SOR_DP_AUDIO_CTRL_0, 0x001f0001); //0x54540188 + SOR_WRITE(SOR_NV_PDISP_SOR_DP_AUDIO_HBLANK_SYMBOLS_0, 0x00000000); //0x5454018c + SOR_WRITE(SOR_NV_PDISP_SOR_DP_AUDIO_VBLANK_SYMBOLS_0, 0x00000000); //0x54540190 + SOR_WRITE(SOR_NV_PDISP_SOR_DP_GENERIC_INFOFRAME_HEADER_0, 0x00000000); //0x54540194 + SOR_WRITE(SOR_NV_PDISP_SOR_DP_GENERIC_INFOFRAME_SUBPACK0_0,0x00000000); //0x54540198 + SOR_WRITE(SOR_NV_PDISP_SOR_DP_GENERIC_INFOFRAME_SUBPACK1_0,0x00000000); //0x5454019c + SOR_WRITE(SOR_NV_PDISP_SOR_DP_GENERIC_INFOFRAME_SUBPACK2_0,0x00000000); //0x545401a0 + SOR_WRITE(SOR_NV_PDISP_SOR_DP_GENERIC_INFOFRAME_SUBPACK3_0,0x00000000); //0x545401a4 + SOR_WRITE(SOR_NV_PDISP_SOR_DP_GENERIC_INFOFRAME_SUBPACK4_0,0x00000000); //0x545401a8 + SOR_WRITE(SOR_NV_PDISP_SOR_DP_GENERIC_INFOFRAME_SUBPACK5_0,0x00000000); //0x545401ac + SOR_WRITE(SOR_NV_PDISP_SOR_DP_GENERIC_INFOFRAME_SUBPACK6_0,0x00000000); //0x545401b0 + SOR_WRITE(SOR_NV_PDISP_SOR_DP_TPG_0, 0x50505050); //0x545401b4 + SOR_WRITE(SOR_NV_PDISP_SOR_DP_TPG_CONFIG_0, 0x00000000); //0x545401b8 + SOR_WRITE(SOR_NV_PDISP_SOR_DP_LQ_CSTM0_0, 0x00000000); //0x545401bc + SOR_WRITE(SOR_NV_PDISP_SOR_DP_LQ_CSTM1_0, 0x00000000); //0x545401c0 + SOR_WRITE(SOR_NV_PDISP_SOR_DP_LQ_CSTM2_0, 0x00000000); //0x545401c4 + printk(BIOS_SPEW, "initial SOR done\n"); +} + +void init_dpaux_regs(void) +{ + struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)TEGRA_CLK_RST_BASE; +// u32 val; + + printk(BIOS_SPEW, "JZ: %s: entry\n", __func__); + +#define SWR_DPAUX_RST (1 << 21) +#define CLK_ENB_DPAUX SWR_DPAUX_RST +// REG(CLK_RST_CONTROLLER_RST_DEVICES_X_0, SWR_DPAUX_RST, 1) +// REG(CLK_RST_CONTROLLER_RST_DEVICES_X_0, SWR_DPAUX_RST, 0) +// REG(CLK_RST_CONTROLLER_CLK_OUT_ENB_X_0, CLK_ENB_DPAUX, 1) + setbits_le32(&clkrst->rst_devices_x, SWR_DPAUX_RST); // Set Reset + clrbits_le32(&clkrst->rst_devices_x, SWR_DPAUX_RST); // Clear Reset + setbits_le32(&clkrst->clk_out_enb_x, CLK_ENB_DPAUX); // Set Enable + +#if 1 +#define DPAUX_WRITE(reg, val) \ + { \ + WRITEL(val, (void *)(TEGRA_ARM_DPAUX + (reg<<2))); \ + } +#define DPAUX_READ(reg) READL( (void *)(TEGRA_ARM_DPAUX + (reg<<2))) + +#else // read back +#define DPAUX_WRITE(reg, val) \ + { \ + printk(BIOS_SPEW,"DPAUX_WRITE: addr %#x = %#x\n", (unsigned int) + (TEGRA_ARM_DPAUX + (reg<<2)), val); \ + WRITEL(val, (void *)(TEGRA_ARM_DPAUX + (reg<<2))); \ + printk(BIOS_SPEW,"= %#x\n", \ + (unsigned int)READL( (void *)(TEGRA_ARM_DPAUX + (reg<<2)))); \ + } +#endif + + DPAUX_WRITE(DPAUX_INTR_EN_AUX, 0x00000000); //0x545c0004 + DPAUX_WRITE(DPAUX_INTR_AUX, 0x00000000); //0x545c0014 + DPAUX_WRITE(DPAUX_DP_AUXDATA_WRITE_W0, 0x00000000); //0x545c0024 + DPAUX_WRITE(DPAUX_DP_AUXDATA_WRITE_W1, 0x00000000); //0x545c0034 + DPAUX_WRITE(DPAUX_DP_AUXDATA_WRITE_W2, 0x00000000); //0x545c0044 + DPAUX_WRITE(DPAUX_DP_AUXDATA_WRITE_W3, 0x00000000); //0x545c0054 + DPAUX_WRITE(DPAUX_DP_AUXDATA_READ_W0, 0x00000000); //0x545c0064 + DPAUX_WRITE(DPAUX_DP_AUXDATA_READ_W1, 0x00000000); //0x545c0074 + DPAUX_WRITE(DPAUX_DP_AUXDATA_READ_W2, 0x00000000); //0x545c0084 + DPAUX_WRITE(DPAUX_DP_AUXDATA_READ_W3, 0x00000000); //0x545c0094 + DPAUX_WRITE(DPAUX_DP_AUXADDR, 0x00000000); //0x545c00a4 + DPAUX_WRITE(DPAUX_DP_AUXCTL, 0x00000000); //0x545c00b4 + DPAUX_WRITE(DPAUX_DP_AUXSTAT, 0x10000000); //0x545c00c4 + DPAUX_WRITE(DPAUX_DP_AUX_SINKSTATLO, 0x00000000); //0x545c00d4 + DPAUX_WRITE(DPAUX_DP_AUX_SINKSTATHI, 0x00000000); //0x545c00e4 + DPAUX_WRITE(DPAUX_HPD_CONFIG, 0x07d000fa); //0x545c00f4 + DPAUX_WRITE(DPAUX_HPD_IRQ_CONFIG, 0x000000fa); //0x545c0104 + DPAUX_WRITE(DPAUX_DP_AUX_CONFIG, 0x00000190); //0x545c0114 + DPAUX_WRITE(DPAUX_HYBRID_PADCTL, 0x00002462); //0x545c0124 + DPAUX_WRITE(DPAUX_HYBRID_SPARE, 0x00000000); //0x545c0134 + DPAUX_WRITE(DPAUX_SCRATCH_REG0_0, 0x00000000); //0x545c0144 + DPAUX_WRITE(DPAUX_SCRATCH_REG1_0, 0x00000000); //0x545c0154 + DPAUX_WRITE(DPAUX_SCRATCH_REG2_0, 0x00000000); //0x545c0164 + printk(BIOS_SPEW, "initial DPAUX done\n"); +} + +static int dp_poll_register(void *addr, u32 exp_val, u32 mask, u32 timeout_ms) +{ + + u32 reg_val = 0; + + printk(BIOS_SPEW, "JZ: %s: enter, addr %#x: exp_val: %#x, mask: %#x\n", + __func__, (unsigned int)addr, exp_val, mask); + do { + udelay(1); + reg_val = READL(addr); + } while (((reg_val & mask) != exp_val) && (--timeout_ms > 0)); + + if ((reg_val & mask) == exp_val) + return 0; /* success */ + printk(BIOS_SPEW, "poll_register %p: timeout\n", addr); + return timeout_ms; +} + +static void dp_io_set_dpd(u32 power_down) +{ + /* + * power_down: + * 0: out of Deep power down + * 1: into deep power down + */ + u32 val_reg; +#define DP_LVDS_SHIFT 25 +#define DP_LVDS (1 << DP_LVDS_SHIFT) + + val_reg = READL((void *)(0x7000e400 + 0x1c4)); /* APBDEV_PMC_IO_DPD2_STATUS_0 */ + printk(BIOS_SPEW, "JZ: %s: enter, into dpd %d, cur_status: %#x\n", + __func__, power_down, val_reg); + + if ((((val_reg & DP_LVDS) >> DP_LVDS_SHIFT) & 1) == power_down) { + printk(BIOS_SPEW, "PAD already POWER=%d\n", 1 - power_down); + return; + } + + /* APBDEV_PMC_IO_DPD2_REQ_0: E_DPD = power on */ + WRITEL((DP_LVDS | ((1 + power_down) << 30)), (void *)(0x7000e400 + 0x1c0)); + + dp_poll_register((void *)(0x7000e400 + 0x1C4), 0, DP_LVDS, 1000); + //APBDEV_PMC_IO_DPD2_STATUS_0 +} + +void dp_io_powerup(void) +{ + +//E_DPD = PMC.dpd2_status[25] +//PDBG = SOR_NV_PDISP_SOR_PLL2_0.AUX6(1) | SEQ.POWERDOWN_MACRO(1) & +//SOR_NV_PDISP_SOR_PLL2_0.AUX2(0) +//PDPLL = SOR_NV_PDISP_SOR_PLL0_0.PWR(1) | SEQ.PDPLL(0) & ~ SOR_NV_PDISP_SOR_PLL2_0.AUX1(0) +//VCOPD = SOR_NV_PDISP_SOR_PLL0_0.VCOPD(1) +//CAPPD = SOR_NV_PDISP_SOR_PLL2_0.AUX8(1) | SEQ.ASSERT_PLL_RESET(0) & +//~ SOR_NV_PDISP_SOR_PLL2_0.AUX1(0) +//PDPORT = SOR_NV_PDISP_SOR_PLL2_0.AUX7(1) | SEQ.PDPORT(1) & +//~ SOR_NV_PDISP_SOR_DP_LINKCTL0_0.ENABLE(0) +//PDCAL = SOR_NV_PDISP_SOR_DP_PADCTL0_0.PAD_CAL_PD(1) + +// struct clk_rst_ctlr *clkrst = +// (struct clk_rst_ctlr *)TEGRA_CLK_RST_BASE; + u32 reg_val; + + printk(BIOS_SPEW, "%s: entry\n", __func__); + +#if 0 + printk(BIOS_SPEW, "JZ: %s: %d: do nothing, ret\n", __func__, __LINE__); + return; +#endif + +#define SOR0_CLK_SEL0 (1 << 14) +#define SOR0_CLK_SEL1 (1 << 15) +// REG(CLK_RST_CONTROLLER_CLK_SOURCE_SOR0_0, SOR0_CLK_SEL1, 0); +// REG(CLK_RST_CONTROLLER_CLK_SOURCE_SOR0_0, SOR0_CLK_SEL0, 0);//sor safe clock + reg_val = READL((void *)(0x60006000 + 0x414)); + reg_val &= ~(SOR0_CLK_SEL0 | SOR0_CLK_SEL1); + WRITEL(reg_val, (void *)(0x60006000 + 0x414)); + +// clock(PLLDP, 270) + WRITEL(0, (void *)(0x60006000 + 0x594)); // plldp_misc + WRITEL(0x11400000, (void *)(0x60006000 + 0x598)); // plldp_ss_cfg + WRITEL(0x80305a01, (void *)(0x60006000 + 0x590));// plldp_base, 12 * 90 / 4 = 270 + WRITEL(0x11400000, (void *)(0x60006000 + 0x598)); // plldp_ss_cfg + WRITEL(0x40000000, (void *)(0x60006000 + 0x594)); // misc: enable lock + WRITEL(0xc0305a01, (void *)(0x60006000 + 0x590)); // base: enable + WRITEL(0xd8305a01, (void *)(0x60006000 + 0x590)); // base: check lock + WRITEL(0x58305a01, (void *)(0x60006000 + 0x590)); // base: disable bypass + WRITEL(0x11000000, (void *)(0x60006000 + 0x598)); // release clamp + udelay(10); // wait for plldp ready + + SOR_WRITE(SOR_NV_PDISP_SOR_CLK_CNTRL_0, (6 << 2) | 2);//select PLLDP, lowest speed(6x) + SOR_WRITE(SOR_NV_PDISP_SOR_DP_PADCTL0_0, 0x00800000); //set PDCAL + SOR_WRITE(SOR_NV_PDISP_SOR_PLL0_0, 0x050003D5); //set PWR,VCOPD + SOR_WRITE(SOR_NV_PDISP_SOR_PLL1_0, 0x00001100); //default + SOR_WRITE(SOR_NV_PDISP_SOR_PLL2_0, 0x01C20000); //set AUX1,6,7,8; clr AUX2 + SOR_WRITE(SOR_NV_PDISP_SOR_PLL3_0, 0x38002220); + + //REG(SOR_NV_PDISP_SOR_PLL3_0,PLLVDD_MODE, V1_8) + dp_io_set_dpd(0); + udelay(1); //Deassert E_DPD to enable core logic circuits, and wait for > 5us + + SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_PLL2_0, + SOR_NV_PDISP_SOR_PLL2_0_AUX6_FIELD, + (0 << SOR_NV_PDISP_SOR_PLL2_0_AUX6_SHIFT)); + udelay(20); //Deassert PDBG to enable bandgap, and wait for > 20us. + + SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_PLL0_0, + SOR_NV_PDISP_SOR_PLL0_0_PWR_FIELD, + (0 << SOR_NV_PDISP_SOR_PLL0_0_PWR_SHIFT)); + SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_PLL0_0, + SOR_NV_PDISP_SOR_PLL0_0_VCOPD_FIELD, + (0 << SOR_NV_PDISP_SOR_PLL0_0_VCOPD_SHIFT)); + SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_PLL2_0, + SOR_NV_PDISP_SOR_PLL2_0_AUX8_FIELD, + (0 << SOR_NV_PDISP_SOR_PLL2_0_AUX8_SHIFT)); + udelay(200); + //Enable the PLL/charge-pump/VCO, and wait for >200us for the PLL to + //lock. Input Clock must be running and stable before PDPLL + //de-assertion. + SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_PLL2_0, + SOR_NV_PDISP_SOR_PLL2_0_AUX7_FIELD, + (0 << SOR_NV_PDISP_SOR_PLL2_0_AUX7_SHIFT)); + SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_PLL2_0, + SOR_NV_PDISP_SOR_PLL2_0_AUX9_FIELD, + (1 << SOR_NV_PDISP_SOR_PLL2_0_AUX9_SHIFT)); + udelay(100); + + printk(BIOS_SPEW, "%s: exit\n", __func__); +} + +static int dpaux_check(u32 bytes, u32 data, u32 mask) +{ + u32 status = 0; + u8 buf[16]; + u32 temp; + + DPAUX_WRITE(DPAUX_DP_AUXDATA_READ_W0, 0); + status = dpaux_read(0x202, bytes, buf); + if (status != 0) + printk(BIOS_SPEW, "******AuxRead Error:%04x: status %08x\n", 0x202, + status); + else { + //temp = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0] ; + //memcpy(&temp, buf, 4); + temp = DPAUX_READ(DPAUX_DP_AUXDATA_READ_W0); + if ((temp & mask) != (data & mask)) { + printk(BIOS_SPEW, "AuxCheck ERROR:(r_data) %08x & (mask) %08x != " + "(data) %08x & (mask) %08x\n", temp, mask, data, mask); + return -1; + } else { + printk(BIOS_SPEW, + "AuxCheck PASS:(bytes=%d,data=%08x,mask=%08x):0x%08x\n", + bytes, data, mask, temp); + return 0; + } + } + return -1; +} + +static void pattern_level(u32 current, u32 preemph, u32 postcur) +{ + printk(BIOS_SPEW, "set level:%d %d %d\n", current, preemph, postcur); + + //calibrating required + if (current == 0) + SOR_WRITE(SOR_NV_PDISP_SOR_LANE_DRIVE_CURRENT0_0, 0x20202020); + if (current == 1) + SOR_WRITE(SOR_NV_PDISP_SOR_LANE_DRIVE_CURRENT0_0, 0x24242424); + if (current == 2) + SOR_WRITE(SOR_NV_PDISP_SOR_LANE_DRIVE_CURRENT0_0, 0x30303030); + if (current == 3) + SOR_WRITE(SOR_NV_PDISP_SOR_LANE_DRIVE_CURRENT0_0, 0x40404040); + if (preemph == 0) + SOR_WRITE(SOR_NV_PDISP_SOR_LANE_PREEMPHASIS0_0, 0x00000000); + if (preemph == 1) + SOR_WRITE(SOR_NV_PDISP_SOR_LANE_PREEMPHASIS0_0, 0x08080808); + if (preemph == 2) + SOR_WRITE(SOR_NV_PDISP_SOR_LANE_PREEMPHASIS0_0, 0x10101010); + if (preemph == 3) + SOR_WRITE(SOR_NV_PDISP_SOR_LANE_PREEMPHASIS0_0, 0x18181818); + if (postcur == 0) + SOR_WRITE(SOR_NV_PDISP_SOR_POSTCURSOR0_0, 0x00000000); + if (postcur == 1) + SOR_WRITE(SOR_NV_PDISP_SOR_POSTCURSOR0_0, 0x04040404); + if (postcur == 2) + SOR_WRITE(SOR_NV_PDISP_SOR_POSTCURSOR0_0, 0x08080808); + if (postcur == 3) + SOR_WRITE(SOR_NV_PDISP_SOR_POSTCURSOR0_0, 0x10101010); +} + +static int dp_training(u32 level, u32 check, u32 speed) +{ + + u32 dc_lv = level & 0x0f; + u32 pe_lv = (level >> 4) & 0x0f; + u32 pc_lv = (level >> 8) & 0x0f; + u32 cnt = 0; + u32 cfg, cfg_d = 0; + u32 wcfg; +// u32 status = 0; + u8 buf[16]; + + while (cnt <= 5) { + pattern_level(dc_lv, pe_lv, pc_lv); + wcfg = (pe_lv << 3) | dc_lv; + if (dc_lv == 3) + wcfg = wcfg | 0x04; + if (pe_lv == 3) + wcfg = wcfg | 0x20; + wcfg = wcfg | (wcfg << 8) | (wcfg << 16) | (wcfg << 24); + dpaux_write(0x103, 4, wcfg); + udelay(50); //100us + DPAUX_WRITE(DPAUX_DP_AUXDATA_READ_W0, 0); + if (!dpaux_check(2, check, check)) + cnt = 100; + else { + dpaux_read(0x206, 1, buf); + cfg = DPAUX_READ(DPAUX_DP_AUXDATA_READ_W0); + cfg &= 0x00ff; + if (cfg == cfg_d) { + ++cnt; + if (cnt > 5) + printk(BIOS_SPEW, "link training FAILED\n"); + } else { + cnt = 0; + cfg_d = cfg; + dc_lv = cfg & 0x3; + pe_lv = (cfg >> 2) & 0x3; + if (speed == 20) { + dpaux_read(0x20C, 1, buf); + cfg = DPAUX_READ(DPAUX_DP_AUXDATA_READ_W0); + pc_lv = cfg & 0x3; + } else { + pc_lv = 0; + } + } + + } + debug_dpaux_print(0x200, 16); + } + + return ((pc_lv << 8) | (pe_lv << 4) | (dc_lv)); + +} + +void dp_link_training(u32 lanes, u32 speed); +void dp_link_training(u32 lanes, u32 speed) +{ + u32 lane_on; + u32 mask, level; + u32 reg_val; + + printk(BIOS_SPEW, "%s: entry, lanes: %d, speed: %d\n", __func__, lanes, + speed); + + printk(BIOS_SPEW, "\nLink training start\n"); + + switch (lanes) { + case 1: + lane_on = 0x04; + break; + case 2: + lane_on = 0x06; + break; + case 4: + lane_on = 0x0f; + break; + default: + printk(BIOS_SPEW, "dp: invalid lane count: %d\n", lanes); + return; + } + + SOR_WRITE(SOR_NV_PDISP_SOR_DP_PADCTL0_0, (0x008000000 | lane_on)); + SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_DP_PADCTL0_0, + SOR_NV_PDISP_SOR_DP_PADCTL0_0_TX_PU_VALUE_FIELD, + (6 << SOR_NV_PDISP_SOR_DP_PADCTL0_0_TX_PU_VALUE_SHIFT)); + SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_DP_PADCTL0_0, + SOR_NV_PDISP_SOR_DP_PADCTL0_0_TX_PU_FIELD, + (1 << SOR_NV_PDISP_SOR_DP_PADCTL0_0_TX_PU_SHIFT)); + SOR_WRITE(SOR_NV_PDISP_SOR_LVDS_0, 0); + + SOR_WRITE(SOR_NV_PDISP_SOR_CLK_CNTRL_0, ((speed << 2) | 2)); + udelay(100); + + //REG(CLK_RST_CONTROLLER_CLK_SOURCE_SOR0_0,SOR0_CLK_SEL0, 1) //sor clk=pad macro output + reg_val = readl((void *)(0x60006000 + 0x414)); + reg_val |= SOR0_CLK_SEL0; +#if 0 // pllp_debug + reg_val &= ~(0x7 << 29); + reg_val |= (0x6 << 29); + reg_val |= (SOR0_CLK_SEL0 | SOR0_CLK_SEL1); +#endif + writel(reg_val, (void *)(0x60006000 + 0x414)); + + SOR_WRITE(SOR_NV_PDISP_SOR_DP_LINKCTL0_0, + (((0xF >> (4 - lanes)) << 16) | 1)); + + SOR_WRITE(SOR_NV_PDISP_SOR_LANE_SEQ_CTL_0, 0x80100000); + printk(BIOS_SPEW, "Polling SOR_NV_PDISP_SOR_LANE_SEQ_CTL_0.DONE\n"); + + dp_poll_register((void *)0x54540084, 0x00000000, 0x80000000, 1000); + + debug_dpaux_print(0x202, 4); + + printk(BIOS_SPEW, "set link rate and lane number: %dMHz, %d lanes\n", + (speed * 27), lanes); + +// printk(BIOS_SPEW,"JZ: dbg ret\n"); +// return; + +// %d = (%lanes<<8) | %speed + dpaux_write(0x100, 2, ((lanes << 8) | speed)); + printk(BIOS_SPEW, "precharge lane 10us\n"); + reg_val = SOR_READ(SOR_NV_PDISP_SOR_DP_PADCTL0_0); + SOR_WRITE(SOR_NV_PDISP_SOR_DP_PADCTL0_0, (0x000000f0 | reg_val)); + udelay(100); + SOR_WRITE(SOR_NV_PDISP_SOR_DP_PADCTL0_0, reg_val); + + printk(BIOS_SPEW, "link training cr start\n"); + SOR_WRITE(SOR_NV_PDISP_SOR_DP_TPG_0, 0x41414141); + dpaux_write(0x102, 1, 0x21); + + mask = 0x0000ffff >> ((4 - lanes) * 4); + level = 0; + level = dp_training(level, 0x1111 & mask, speed); + printk(BIOS_SPEW, "level:%x\n", level); + + debug_dpaux_print(0x210, 16); + + printk(BIOS_SPEW, "link training eq start\n"); + if (speed == 20) { + SOR_WRITE(SOR_NV_PDISP_SOR_DP_TPG_0, 0x43434343); + dpaux_write(0x102, 1, 0x23); + } else { + SOR_WRITE(SOR_NV_PDISP_SOR_DP_TPG_0, 0x42424242); + dpaux_write(0x102, 1, 0x22); + } + + level = dp_training(level, (0x7777 & mask) | 0x10000, speed); + printk(BIOS_SPEW, "level:%x\n", level); + + debug_dpaux_print(0x210, 16); + + SOR_WRITE(SOR_NV_PDISP_SOR_DP_TPG_0, 0x50505050); + dpaux_write(0x102, 1, 0); + dpaux_write(0x600, 1, 1); + + debug_dpaux_print(0x200, 16); + debug_dpaux_print(0x210, 16); + + printk(BIOS_SPEW, "Link training done\n\n"); + printk(BIOS_SPEW, "%s: exit\n", __func__); +} + +static u32 div_f(u32 a, u32 b, u32 one) +{ + u32 d = (((a - (a / b * b)) * one) + (b / 2)) / b; + return (d); +} + +u32 dp_setup_timing(u32 panel_id, u32 width, u32 height); +u32 dp_setup_timing(u32 panel_id, u32 width, u32 height) +{ + u32 reg_val; + u32 pclk_freq = 0; + + /////////////////////////////////////////// + // set up clocks, using PLLD2 + // format: pclk , PLL , panel + //2560x1440: 241.5 , 483/2, dp VESA.red. + //1920x1080: 148.5 , 594/4, dp CEA + //1600x1200: 161.0 , 483/3, dp VESA + //1280x 720: 74.25 , 594/8, dp CEA + // 1024x768: 63.5 , 508/8, dp VESA + // 800x600: 38.25 , 459/12, dp VESA + // 720x480: 27.00 , 594/22, dp CEA + // 640x480: 23.75 , 475/20, dp VESA + +#if 0 + //LG 12.85", 285.25MHz, neg hsync/vsync + // 2560 x 1700 + //hfrontporch=48, hsyncwidth=32, hbackporch=80 + //vfrontporch=3, vsyncwidth=10, vbackporch=36 + %PLL_FREQ = 570 + % PLL_DIV = 2 + % SYNC_WIDTH = (10 << 16) | 32 + % BACK_PORCH = (36 << 16) | 80 + % FRONT_PORCH = (3 << 16) | 48 % HSYNC_NEG = 1 % VSYNC_NEG = 1 +#endif + u32 PLL_FREQ = 570; + u32 PLL_DIV = 2; + u32 SYNC_WIDTH = (10 << 16) | 32; + u32 BACK_PORCH = (36 << 16) | 80; + u32 FRONT_PORCH = (3 << 16) | 48; + u32 HSYNC_NEG = 1; + u32 VSYNC_NEG = 1; + + u32 SHIFT_CLK_DIVIDER = PLL_DIV * 2 - 2; + u32 DISP_ACTIVE = (height << 16) | width; + u32 DISP_TOTAL = DISP_ACTIVE + SYNC_WIDTH + BACK_PORCH + FRONT_PORCH; + u32 SYNC_END = SYNC_WIDTH - 0x10001; + u32 BLANK_END = SYNC_END + BACK_PORCH; + u32 BLANK_START = BLANK_END + DISP_ACTIVE; + u32 TOTAL_PIXELS = (DISP_TOTAL & 0xffff) * (DISP_TOTAL >> 16); + + u32 PLL_FREQ_I, PLL_FREQ_F; + u32 PCLK_FREQ_I, PCLK_FREQ_F; + u32 FRATE_I, FRATE_F; + + printk(BIOS_SPEW, "%s: entry\n", __func__); + + if (panel_id != 5) { + printk(BIOS_SPEW, "%s: Unsupported panel_id: %d, format=%dx%d\n", + __func__, panel_id, width, height); + return pclk_freq; + } +#if 1 // jz +// clock(plld2, %PLL_FREQ) // PLL_FREQ = 570 + writel(0, (void *)(0x60006000 + 0x4bc)); // plld2_misc + writel(0x13400000, (void *)(0x60006000 + 0x570)); // plld2_ss_cfg + writel(0x8008010c, (void *)(0x60006000 + 0x4b8)); // plld2_base + writel(0x80105F01, (void *)(0x60006000 + 0x4b8));// plld2_base: 12 * 95 / 2 = 570 + writel(0x40000000, (void *)(0x60006000 + 0x4bc)); // misc: enable lock + writel(0x80105f01, (void *)(0x60006000 + 0x4b8)); // base: enable + writel(0xc0105f01, (void *)(0x60006000 + 0x4b8)); // base: check lock + writel(0x58105f01, (void *)(0x60006000 + 0x4b8)); // base: disable bypass + writel(0x13800000, (void *)(0x60006000 + 0x570)); // plld2_ss_cfg + udelay(10); // wait for plld2 ready + +// REG(CLK_RST_CONTROLLER_CLK_SOURCE_DISP1_0, DISP1_CLK_SRC, PLLD2_OUT0) +#define DISP1_CLK_SRC (0x7 << 29) +#define PLLD2_OUT0 (0x5 << 29) + reg_val = readl((void *)(0x60006000 + 0x138)); + reg_val &= ~DISP1_CLK_SRC; + reg_val |= PLLD2_OUT0; + writel(reg_val, (void *)(0x60006000 + 0x138)); + udelay(10); +#endif + PLL_FREQ = PLL_FREQ * 1000000; + pclk_freq = PLL_FREQ / PLL_DIV; + PLL_FREQ_I = PLL_FREQ / 1000000; + PLL_FREQ_F = div_f(PLL_FREQ, 1000000, 100); + PCLK_FREQ_I = PLL_FREQ / (PLL_DIV * 1000000); + PCLK_FREQ_F = div_f(PLL_FREQ, PLL_DIV * 1000000, 100); + FRATE_I = PLL_FREQ / (PLL_DIV * TOTAL_PIXELS); + FRATE_F = div_f(PLL_FREQ, (PLL_DIV * TOTAL_PIXELS), 100); + //bug 1021453 + BACK_PORCH = BACK_PORCH - 0x10000; + FRONT_PORCH = FRONT_PORCH + 0x10000; + + printk(BIOS_SPEW, "ACTIVE: %dx%d\n", (DISP_ACTIVE & 0xFFFF), + (DISP_ACTIVE >> 16)); + printk(BIOS_SPEW, "TOTAL: %dx%d\n", (DISP_TOTAL & 0xffff), + (DISP_TOTAL >> 16)); + printk(BIOS_SPEW, "PLL Freq: %d.%d MHz\n", PLL_FREQ_I, PLL_FREQ_F); + printk(BIOS_SPEW, "Pclk Freq: %d.%d MHz\n", PCLK_FREQ_I, + PCLK_FREQ_F); + printk(BIOS_SPEW, "Frame Rate: %d.%d Hz\n", FRATE_I, FRATE_F); + printk(BIOS_SPEW, "\n"); + + DCA_WRITE(DC_CMD_STATE_ACCESS_0, 0x00000004); + DCA_WRITE(DC_DISP_DISP_CLOCK_CONTROL_0, SHIFT_CLK_DIVIDER); + //Raster Timing + DCA_WRITE(DC_DISP_DISP_TIMING_OPTIONS_0, 0x00000001); + DCA_WRITE(DC_DISP_REF_TO_SYNC_0, 0x00010001); + DCA_WRITE(DC_DISP_SYNC_WIDTH_0, SYNC_WIDTH); + DCA_WRITE(DC_DISP_BACK_PORCH_0, BACK_PORCH); + DCA_WRITE(DC_DISP_DISP_ACTIVE_0, DISP_ACTIVE); + DCA_WRITE(DC_DISP_FRONT_PORCH_0, FRONT_PORCH); + + printk(BIOS_SPEW, + "JZ: sync_width: %d, back_porch: %d, disp_active: %d, front_porch: %d\n", + SYNC_WIDTH, BACK_PORCH, DISP_ACTIVE, FRONT_PORCH); + //REG(DC_DISP_DISP_WIN_OPTIONS_0, SOR_ENABLE , 1) + DCA_READ_M_WRITE(DC_DISP_DISP_WIN_OPTIONS_0, + DC_DISP_DISP_WIN_OPTIONS_0_SOR_ENABLE_FIELD, + (1 << DC_DISP_DISP_WIN_OPTIONS_0_SOR_ENABLE_SHIFT)); + + SOR_WRITE(SOR_NV_PDISP_HEAD_STATE1_0, DISP_TOTAL); + SOR_WRITE(SOR_NV_PDISP_HEAD_STATE2_0, SYNC_END); + SOR_WRITE(SOR_NV_PDISP_HEAD_STATE3_0, BLANK_END); + SOR_WRITE(SOR_NV_PDISP_HEAD_STATE4_0, BLANK_START); + + SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_STATE1_0, + SOR_NV_PDISP_SOR_STATE1_0_ASY_HSYNCPOL_FIELD, + (HSYNC_NEG << + SOR_NV_PDISP_SOR_STATE1_0_ASY_HSYNCPOL_SHIFT)); + + SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_STATE1_0, + SOR_NV_PDISP_SOR_STATE1_0_ASY_VSYNCPOL_FIELD, + (VSYNC_NEG << + SOR_NV_PDISP_SOR_STATE1_0_ASY_VSYNCPOL_SHIFT)); + + SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_STATE1_0, + SOR_NV_PDISP_SOR_STATE1_0_ASY_PROTOCOL_FIELD, + (SOR_NV_PDISP_SOR_STATE1_0_ASY_PROTOCOL_DP_A << + SOR_NV_PDISP_SOR_STATE1_0_ASY_PROTOCOL_SHIFT)); + + SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_STATE1_0, + SOR_NV_PDISP_SOR_STATE1_0_ASY_CRCMODE_FIELD, + (SOR_NV_PDISP_SOR_STATE1_0_ASY_CRCMODE_COMPLETE_RASTER << + SOR_NV_PDISP_SOR_STATE1_0_ASY_CRCMODE_SHIFT)); + + SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_STATE1_0, + SOR_NV_PDISP_SOR_STATE1_0_ASY_SUBOWNER_FIELD, + (SOR_NV_PDISP_SOR_STATE1_0_ASY_SUBOWNER_NONE << + SOR_NV_PDISP_SOR_STATE1_0_ASY_SUBOWNER_SHIFT)); + + SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_STATE1_0, + SOR_NV_PDISP_SOR_STATE1_0_ASY_OWNER_FIELD, + (SOR_NV_PDISP_SOR_STATE1_0_ASY_OWNER_HEAD0 << + SOR_NV_PDISP_SOR_STATE1_0_ASY_OWNER_SHIFT)); +#if 0 // ts + + %SHIFT_CLK_DIVIDER = %PLL_DIV * 2 - 2 + % DISP_ACTIVE = (%HEIGHT << 16) | %WIDTH + % DISP_TOTAL = %DISP_ACTIVE + %SYNC_WIDTH + %BACK_PORCH + %FRONT_PORCH + % SYNC_END = %SYNC_WIDTH - 0x10001 + % BLANK_END = %SYNC_END + %BACK_PORCH + % BLANK_START = %BLANK_END + %DISP_ACTIVE + % TOTAL_PIXELS = (%DISP_TOTAL & 0xffff) * (%DISP_TOTAL >> 16) + + % pclk_freq = %PLL_FREQ / %PLL_DIV + % PLL_FREQ_I = %PLL_FREQ / 1000000 + % PLL_FREQ_F = div_f(%PLL_FREQ, 1000000, 100) + % PCLK_FREQ_I = %PLL_FREQ / (%PLL_DIV * 1000000) + % PCLK_FREQ_F = div_f(%PLL_FREQ, %PLL_DIV * 1000000, 100) + % FRATE_I = %PLL_FREQ / (%PLL_DIV * %TOTAL_PIXELS) + % FRATE_F = div_f(%PLL_FREQ, (%PLL_DIV * %TOTAL_PIXELS), 100) + //bug 1021453 + % BACK_PORCH = %BACK_PORCH - 0x10000 + % FRONT_PORCH = %FRONT_PORCH + 0x10000 + printk(BIOS_SPEW, "ACTIVE: %dx%d\n", (%DISP_ACTIVE & 0xFFFF), + (%DISP_ACTIVE >> 16)) + printk(BIOS_SPEW, "TOTAL: %dx%d\n", (%DISP_TOTAL & 0xffff), + (%DISP_TOTAL >> 16)) + printk(BIOS_SPEW, "PLL Freq: %d.%d MHz\n", %PLL_FREQ_I, + %PLL_FREQ_F) + printk(BIOS_SPEW, "Pclk Freq: %d.%d MHz\n", %PCLK_FREQ_I, + %PCLK_FREQ_F) + printk(BIOS_SPEW, "Frame Rate: %d.%d Hz\n", %FRATE_I, %FRATE_F) + printk(BIOS_SPEW, "\n") + + REG(DC_CMD_STATE_ACCESS_0, 0x00000004) + REG(DC_DISP_DISP_CLOCK_CONTROL_0, %SHIFT_CLK_DIVIDER) + //Raster Timing + REG(DC_DISP_DISP_TIMING_OPTIONS_0, 0x00000001) + REG(DC_DISP_REF_TO_SYNC_0, 0x00010001) + REG(DC_DISP_SYNC_WIDTH_0, %SYNC_WIDTH) + REG(DC_DISP_BACK_PORCH_0, %BACK_PORCH) + REG(DC_DISP_DISP_ACTIVE_0, %DISP_ACTIVE) + REG(DC_DISP_FRONT_PORCH_0, %FRONT_PORCH) + + REG(DC_DISP_DISP_WIN_OPTIONS_0, SOR_ENABLE, 1) + REG(SOR_NV_PDISP_HEAD_STATE1_0, %DISP_TOTAL) + REG(SOR_NV_PDISP_HEAD_STATE2_0, %SYNC_END) + REG(SOR_NV_PDISP_HEAD_STATE3_0, %BLANK_END) + REG(SOR_NV_PDISP_HEAD_STATE4_0, %BLANK_START) + REG(SOR_NV_PDISP_SOR_STATE1_0, ASY_HSYNCPOL, %HSYNC_NEG) + REG(SOR_NV_PDISP_SOR_STATE1_0, ASY_VSYNCPOL, %VSYNC_NEG) + REG(SOR_NV_PDISP_SOR_STATE1_0, ASY_PROTOCOL, DP_A) + REG(SOR_NV_PDISP_SOR_STATE1_0, ASY_CRCMODE, COMPLETE_RASTER) + REG(SOR_NV_PDISP_SOR_STATE1_0, ASY_SUBOWNER, NONE) + REG(SOR_NV_PDISP_SOR_STATE1_0, ASY_OWNER, HEAD0) + return (%pclk_freq) +#endif + printk(BIOS_SPEW, "%s: exit\n", __func__); + return pclk_freq; +} + +static u32 calc_config(u32 ts, u32 a, u32 b, u32 bpp) +{ + u32 act_cnt = (ts * a) / b; + u32 diff = (ts * a) - (act_cnt * b); + u32 act_pol; + u32 act_frac; + u32 err; + u32 water_mark; + printk(BIOS_SPEW, "calc_config ts %d a %d b %d bpp %d\n", ts, a, b, bpp); + if (diff != 0) { + if (diff > (b / 2)) { + diff = b - diff; + act_pol = 1; + act_frac = (b + diff - 1) / diff; + err = diff * act_frac - b; + } else { + act_pol = 0; + act_frac = b / diff; + err = b - (diff * act_frac); + } + if (act_frac > 15) { + act_pol = 1 - act_pol; + act_frac = 1; + err = diff; + } + } else { + act_pol = 1; + act_frac = 1; + err = 0; + } + + if (bpp) { + water_mark = (a * (b - a) * ts / (b * b)) + (2 * bpp / 8); + if (water_mark > 30) + water_mark = 30; + + SOR_WRITE(SOR_NV_PDISP_SOR_DP_CONFIG0_0, 0x84000000); + SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_DP_CONFIG0_0, + SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_POLARITY_FIELD, + (act_pol << + SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_POLARITY_SHIFT)); + SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_DP_CONFIG0_0, + SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_FRAC_FIELD, + (act_frac << + SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_FRAC_SHIFT)); + SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_DP_CONFIG0_0, + SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_COUNT_FIELD, + (act_cnt << + SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_COUNT_SHIFT)); + SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_DP_CONFIG0_0, + SOR_NV_PDISP_SOR_DP_CONFIG0_0_WATERMARK_FIELD, + (water_mark << + SOR_NV_PDISP_SOR_DP_CONFIG0_0_WATERMARK_SHIFT)); + + printk(BIOS_SPEW, + "SOR_DP_CONFIG0:TU,CNT,POL,FRAC,WMK,ERR=%d,%d,%d,%d,%d,%d/%d\n", + ts, act_cnt, act_pol, act_frac, water_mark, err, b); + } + return (err); +} + +static u32 dp_buf_config(u32 pclkfreq, u32 linkfreq, u32 lanes, u32 bpp) +{ + //to avoid 32bit overflow + u32 tusize = 0; + u32 pf = pclkfreq; + u32 lf = linkfreq; + u32 i; + u32 a, b; + u32 min_err = 1000000000; + u32 ts = 64; + u32 c_err; + printk(BIOS_SPEW, "dp buf config pclkfreq %d linkfreq %d lanes %d bpp %d\n", + pclkfreq, linkfreq, lanes, bpp); + for (i = 2; i <= 7; ++i) { + while (((pf / i * i) == pf) && ((lf / i * i) == lf)) { + pf = pf / i; + lf = lf / i; + } + } + + a = pf * bpp / 8; + b = lf * lanes; + printk(BIOS_SPEW, "ratio:%d/%d\n", a, b); + if (a > (b * 98 / 100)) + printk(BIOS_SPEW, "Error:link speed not enough\n"); + + //search best tusize + //min_err = 1000000000; + //ts = 64; + while (ts >= 32) { + c_err = calc_config(ts, a, b, 0); + if (c_err < min_err) { + if (c_err == 0) { + tusize = ts; + ts = 1; + } else { + min_err = c_err; + tusize = ts; + } + } + --ts; + } + + SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_DP_LINKCTL0_0, + SOR_NV_PDISP_SOR_DP_LINKCTL0_0_TUSIZE_FIELD, + (tusize << SOR_NV_PDISP_SOR_DP_LINKCTL0_0_TUSIZE_SHIFT)); + calc_config(tusize, a, b, bpp); + + return (tusize); +} + +void dp_misc_setting(u32 panel_bpp, u32 width, u32 height, u32 winb_addr, + u32 lane_count, u32 enhanced_framing, u32 panel_edp, + u32 pclkfreq, u32 linkfreq); + +void dp_misc_setting(u32 panel_bpp, u32 width, u32 height, u32 winb_addr, + u32 lane_count, u32 enhanced_framing, u32 panel_edp, + u32 pclkfreq, u32 linkfreq) +{ + u32 tusize; + u32 linkctl; + + printk(BIOS_SPEW, "%s: entry, winb: 0x%08x ", __func__, winb_addr); + printk(BIOS_SPEW, " panel_bpp %d\n", panel_bpp); + + if (panel_bpp == 18) { + //0x54540010 + SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_STATE1_0, + SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_FIELD, + (SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_BPP_18_444 << + SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_SHIFT)); + } + if (panel_bpp == 24) { + SOR_READ_M_WRITE(SOR_NV_PDISP_SOR_STATE1_0, + SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_FIELD, + (SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_BPP_24_444 << + SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_SHIFT)); + } +#if 0 +#define DC_B_WIN_BD_SIZE_0 0xd84 +#define DC_B_WIN_BD_PRESCALED_SIZE_0 0xd86 +#define DC_B_WIN_BD_LINE_STRIDE_0 0xd8a +#define DC_B_WIN_BD_COLOR_DEPTH_0 0xd83 +#define DC_B_WINBUF_BD_START_ADDR_0 0xdc0 +#define DC_B_WIN_BD_DDA_INCREMENT_0 0xd89 +#endif + +#define SRC_BPP 16 +#define COLORDEPTH 0x6 + +#define BLUE 0xFF0000 +#define GREEN 0x00FF00 +#define RED 0x0000FF +#define YELLOW 0x00FFFF +#define BLACK 0x000000 +#define WHITE 0xFFFFFF +#define GREY 0x55aa00 + + DCA_WRITE(DC_B_WIN_BD_SIZE_0, ((height << 16) | width)); + DCA_WRITE(DC_B_WIN_BD_PRESCALED_SIZE_0, + ((height << 16) | (width * SRC_BPP / 8))); + DCA_WRITE(DC_B_WIN_BD_LINE_STRIDE_0, + ((width * SRC_BPP / 8 + 31) / 32 * 32)); + DCA_WRITE(DC_B_WIN_BD_COLOR_DEPTH_0, COLORDEPTH); + DCA_WRITE(DC_B_WINBUF_BD_START_ADDR_0, winb_addr); + DCA_WRITE(DC_B_WIN_BD_DDA_INCREMENT_0, 0x10001000); + + SOR_WRITE(SOR_NV_PDISP_SOR_CRC_CNTRL_0, 0x00000001); + DCA_WRITE(DC_COM_CRC_CONTROL_0, 0x00000009); //CRC_ALWAYS+CRC_ENABLE + DCA_WRITE(DC_COM_PIN_OUTPUT_ENABLE2_0, 0x00000000); + DCA_WRITE(DC_COM_PIN_OUTPUT_ENABLE3_0, 0x00000000); + DCA_WRITE(DC_DISP_DISP_SIGNAL_OPTIONS0_0, 0x00000000); + // DCA_WRITE (DC_DISP_BLEND_BACKGROUND_COLOR_0 ,WHITE ); + DCA_WRITE(DC_DISP_BLEND_BACKGROUND_COLOR_0, YELLOW); + DCA_WRITE(DC_CMD_DISPLAY_COMMAND_0, 0x00000020); + SOR_WRITE(SOR_NV_PDISP_SOR_DP_AUDIO_VBLANK_SYMBOLS_0, 0x00000e48); + + //AuxPrint(0x200, 16) + + // %d = (%enhanced_framing << 7) | %lanes + dpaux_write(0x101, 1, (enhanced_framing << 7) | lane_count); + if (panel_edp) + dpaux_write(0x10A, 1, 1); + + tusize = + dp_buf_config(pclkfreq, (linkfreq * 1000000), lane_count, panel_bpp); + + printk(BIOS_SPEW, "JZ, after dp_buf_config, tusize: 0x%08x\n", tusize); + + linkctl = + ((0xF >> (4 - lane_count)) << 16) | (enhanced_framing << 14) | (tusize + << 2) | + 1; + + SOR_WRITE(SOR_NV_PDISP_SOR_DP_LINKCTL0_0, linkctl); + SOR_WRITE(SOR_NV_PDISP_SOR_DP_SPARE0_0, ((panel_edp << 1) | 0x05)); + + SOR_WRITE(SOR_NV_PDISP_SOR_PWR_0, 0x80000001); + printk(BIOS_SPEW, "Polling SOR_NV_PDISP_SOR_PWR_0.DONE\n"); + dp_poll_register((void *)0x54540054, 0x00000000, 0x80000000, 1000); + //SOR_NV_PDISP_SOR_PWR_0 + //sor_update + SOR_WRITE(SOR_NV_PDISP_SOR_STATE0_0, 0x00000000); + SOR_WRITE(SOR_NV_PDISP_SOR_SUPER_STATE1_0, 0x00000006); + //sor_super_update + SOR_WRITE(SOR_NV_PDISP_SOR_SUPER_STATE0_0, 0x00000000); + SOR_WRITE(SOR_NV_PDISP_SOR_SUPER_STATE1_0, 0x0000000e); + //sor_super_update + SOR_WRITE(SOR_NV_PDISP_SOR_SUPER_STATE0_0, 0x00000000); + printk(BIOS_SPEW, "Polling SOR_NV_PDISP_SOR_TEST_0.ATTACHED\n"); + dp_poll_register((void *)0x54540058, 0x00000400, 0x00000400, 1000); + //SOR_NV_PDISP_SOR_TEST_0 + + DCA_WRITE(DC_CMD_STATE_CONTROL_0, 0x00009f00); + DCA_WRITE(DC_CMD_STATE_CONTROL_0, 0x0000009f); + DCA_WRITE(DC_CMD_DISPLAY_POWER_CONTROL_0, 0x00050155); + + printk(BIOS_SPEW, "Polling SOR_NV_PDISP_SOR_TEST_0.AWAKE\n"); + dp_poll_register((void *)0x54540058, 0x00000200, 0x00000300, 1000); + //SOR_NV_PDISP_SOR_TEST_0 + + // DCA_WRITE (DC_CMD_STATE_ACCESS_0 ,0); + DCA_WRITE(DC_CMD_STATE_ACCESS_0, 4); + DCA_WRITE(DC_CMD_STATE_CONTROL_0, 0x0000ffff); + /* enable win_b */ +#if 1 + DCA_READ_M_WRITE(DC_B_WIN_BD_WIN_OPTIONS_0, + DC_B_WIN_BD_WIN_OPTIONS_0_BD_WIN_ENABLE_FIELD, + (DC_B_WIN_BD_WIN_OPTIONS_0_BD_WIN_ENABLE_ENABLE << + DC_B_WIN_BD_WIN_OPTIONS_0_BD_WIN_ENABLE_SHIFT)); +#endif + + printk(BIOS_SPEW, "JZ: %s: f_ret @ line %d\n", __func__, __LINE__); +} + +static inline void dc_act(void) +{ + DCA_WRITE(DC_CMD_STATE_CONTROL_0, 0x0000ffff); +} + +void dp_test(void); +void dp_test(void) +{ + u32 color = BLACK; + u32 final = GREY; + u32 i; + + printk(BIOS_SPEW, "%s: entry\n", __func__); + + for (i = 0; i < 10; ++i) { + printk(BIOS_SPEW, "TEST %d\n", i); + switch (i % 3) { + case 0: + color = RED; + case 1: + color = GREEN; + case 2: + color = BLUE; + } + + DCA_WRITE(DC_DISP_BLEND_BACKGROUND_COLOR_0, color); + dc_act(); + delay(5); + } + + DCA_WRITE(DC_DISP_BLEND_BACKGROUND_COLOR_0, final); + dc_act(); + udelay(1500); + +// DCA_WRITE (DC_DISP_BLEND_BACKGROUND_COLOR_0, BLACK); +// dc_act(); +// udelay(1500); + + DCA_WRITE(DC_CMD_STATE_ACCESS_0, 4); + dc_act(); + + printk(BIOS_SPEW, "%s: exit\n", __func__); +} diff --git a/src/soc/nvidia/tegra124/include/soc/addressmap.h b/src/soc/nvidia/tegra124/include/soc/addressmap.h index 536b53d793..c4bdaa8b8e 100644 --- a/src/soc/nvidia/tegra124/include/soc/addressmap.h +++ b/src/soc/nvidia/tegra124/include/soc/addressmap.h @@ -32,6 +32,8 @@ enum { TEGRA_ARM_PERIPHBASE = 0x50040000, TEGRA_ARM_DISPLAYA = 0x54200000, TEGRA_ARM_DISPLAYB = 0x54240000, + TEGRA_ARM_SOR = 0x54540000, + TEGRA_ARM_DPAUX = 0x545c0000, TEGRA_PG_UP_BASE = 0x60000000, TEGRA_TMRUS_BASE = 0x60005010, TEGRA_CLK_RST_BASE = 0x60006000, diff --git a/src/soc/nvidia/tegra124/include/soc/display.h b/src/soc/nvidia/tegra124/include/soc/display.h index 8c7e3e7b17..868fee416b 100644 --- a/src/soc/nvidia/tegra124/include/soc/display.h +++ b/src/soc/nvidia/tegra124/include/soc/display.h @@ -18,5 +18,8 @@ #define __SOC_NVIDIA_TEGRA124_INCLUDE_SOC_DISPLAY_H__ void setup_display(struct soc_nvidia_tegra124_config *config); - +void init_dca_regs(void); +void init_dpaux_regs(void); +void init_sor_regs(void); +void dp_io_powerup(void); #endif /* __SOC_NVIDIA_TEGRA124_INCLUDE_SOC_DISPLAY_H__ */