Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 1 | /* |
Stefan Reinauer | 08dc357 | 2013-05-14 16:57:50 -0700 | [diff] [blame] | 2 | * This file is part of the coreboot project. |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 3 | * |
Stefan Reinauer | 08dc357 | 2013-05-14 16:57:50 -0700 | [diff] [blame] | 4 | * Copyright (C) 2012 Samsung Electronics |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 5 | * |
Stefan Reinauer | 08dc357 | 2013-05-14 16:57:50 -0700 | [diff] [blame] | 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; version 2 of the License. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 14 | */ |
| 15 | |
Stefan Reinauer | 08dc357 | 2013-05-14 16:57:50 -0700 | [diff] [blame] | 16 | /* Samsung DP (Display port) register interface driver. */ |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 17 | |
Stefan Reinauer | 08dc357 | 2013-05-14 16:57:50 -0700 | [diff] [blame] | 18 | #include <arch/io.h> |
Julius Werner | 1ed0c8c | 2014-10-20 13:16:29 -0700 | [diff] [blame] | 19 | #include <console/console.h> |
Stefan Reinauer | 08dc357 | 2013-05-14 16:57:50 -0700 | [diff] [blame] | 20 | #include <delay.h> |
Julius Werner | 1ed0c8c | 2014-10-20 13:16:29 -0700 | [diff] [blame] | 21 | #include <soc/clk.h> |
| 22 | #include <soc/cpu.h> |
| 23 | #include <soc/dp.h> |
| 24 | #include <soc/dp-core.h> |
| 25 | #include <soc/fimd.h> |
| 26 | #include <soc/periph.h> |
| 27 | #include <timer.h> |
Ronald G. Minnich | 7576f25 | 2013-04-09 14:39:34 -0700 | [diff] [blame] | 28 | |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 29 | void s5p_dp_reset(struct s5p_dp_device *dp) |
| 30 | { |
| 31 | u32 reg; |
| 32 | struct exynos5_dp *base = dp->base; |
| 33 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 34 | write32(&base->dp_tx_sw_reset, RESET_DP_TX); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 35 | |
| 36 | /* Stop Video */ |
| 37 | clrbits_le32(&base->video_ctl_1, VIDEO_EN); |
| 38 | clrbits_le32(&base->video_ctl_1, HDCP_VIDEO_MUTE); |
| 39 | |
| 40 | reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N | |
| 41 | AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N | |
| 42 | HDCP_FUNC_EN_N | SW_FUNC_EN_N; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 43 | write32(&base->func_en_1, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 44 | |
| 45 | reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N | |
| 46 | SERDES_FIFO_FUNC_EN_N | |
| 47 | LS_CLK_DOMAIN_FUNC_EN_N; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 48 | write32(&base->func_en_2, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 49 | |
| 50 | udelay(20); |
| 51 | |
| 52 | reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 | |
| 53 | LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0; |
| 54 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 55 | write32(&base->lane_map, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 56 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 57 | write32(&base->sys_ctl_1, 0x0); |
| 58 | write32(&base->sys_ctl_2, 0x40); |
| 59 | write32(&base->sys_ctl_3, 0x0); |
| 60 | write32(&base->sys_ctl_4, 0x0); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 61 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 62 | write32(&base->pkt_send_ctl, 0x0); |
| 63 | write32(&base->dp_hdcp_ctl, 0x0); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 64 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 65 | write32(&base->dp_hpd_deglitch_l, 0x5e); |
| 66 | write32(&base->dp_hpd_deglitch_h, 0x1a); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 67 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 68 | write32(&base->dp_debug_ctl, 0x10); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 69 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 70 | write32(&base->dp_phy_test, 0x0); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 71 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 72 | write32(&base->dp_video_fifo_thrd, 0x0); |
| 73 | write32(&base->dp_audio_margin, 0x20); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 74 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 75 | write32(&base->m_vid_gen_filter_th, 0x4); |
| 76 | write32(&base->m_aud_gen_filter_th, 0x2); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 77 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 78 | write32(&base->soc_general_ctl, 0x00000101); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 79 | |
| 80 | /* Set Analog Parameters */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 81 | write32(&base->analog_ctl_1, 0x10); |
| 82 | write32(&base->analog_ctl_2, 0x0C); |
| 83 | write32(&base->analog_ctl_3, 0x85); |
| 84 | write32(&base->pll_filter_ctl_1, 0x66); |
| 85 | write32(&base->tx_amp_tuning_ctl, 0x0); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 86 | |
| 87 | /* Set interrupt pin assertion polarity as high */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 88 | write32(&base->int_ctl, INT_POL0 | INT_POL1); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 89 | |
Martin Roth | 4c3ab73 | 2013-07-08 16:23:54 -0600 | [diff] [blame] | 90 | /* Clear pending registers */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 91 | write32(&base->common_int_sta_1, 0xff); |
| 92 | write32(&base->common_int_sta_2, 0x4f); |
| 93 | write32(&base->common_int_sta_3, 0xe0); |
| 94 | write32(&base->common_int_sta_4, 0xe7); |
| 95 | write32(&base->dp_int_sta, 0x63); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 96 | |
| 97 | /* 0:mask,1: unmask */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 98 | write32(&base->common_int_mask_1, 0x00); |
| 99 | write32(&base->common_int_mask_2, 0x00); |
| 100 | write32(&base->common_int_mask_3, 0x00); |
| 101 | write32(&base->common_int_mask_4, 0x00); |
| 102 | write32(&base->int_sta_mask, 0x00); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 103 | } |
| 104 | |
| 105 | unsigned int s5p_dp_get_pll_lock_status(struct s5p_dp_device *dp) |
| 106 | { |
| 107 | u32 reg; |
| 108 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 109 | reg = read32(&dp->base->dp_debug_ctl); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 110 | if (reg & PLL_LOCK) |
| 111 | return PLL_LOCKED; |
| 112 | else |
| 113 | return PLL_UNLOCKED; |
| 114 | } |
| 115 | |
| 116 | int s5p_dp_init_analog_func(struct s5p_dp_device *dp) |
| 117 | { |
| 118 | u32 reg; |
Aaron Durbin | 4393346 | 2014-09-24 10:27:29 -0500 | [diff] [blame] | 119 | struct stopwatch sw; |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 120 | struct exynos5_dp *base = dp->base; |
| 121 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 122 | write32(&base->dp_phy_pd, 0x00); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 123 | |
| 124 | reg = PLL_LOCK_CHG; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 125 | write32(&base->common_int_sta_1, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 126 | |
| 127 | clrbits_le32(&base->dp_debug_ctl, (F_PLL_LOCK | PLL_LOCK_CTRL)); |
| 128 | |
| 129 | /* Power up PLL */ |
| 130 | if (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { |
| 131 | |
| 132 | clrbits_le32(&base->dp_pll_ctl, DP_PLL_PD); |
| 133 | |
Aaron Durbin | 4393346 | 2014-09-24 10:27:29 -0500 | [diff] [blame] | 134 | stopwatch_init_msecs_expire(&sw, PLL_LOCK_TIMEOUT); |
Gabe Black | 9b764a0 | 2013-07-30 15:11:35 -0700 | [diff] [blame] | 135 | |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 136 | while (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { |
Aaron Durbin | 4393346 | 2014-09-24 10:27:29 -0500 | [diff] [blame] | 137 | if (stopwatch_expired(&sw)) { |
Ronald G. Minnich | 2810afa | 2013-04-18 18:09:24 -0700 | [diff] [blame] | 138 | printk(BIOS_ERR, "%s: PLL is not locked\n", |
| 139 | __func__); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 140 | return -1; |
| 141 | } |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | /* Enable Serdes FIFO function and Link symbol clock domain module */ |
| 146 | clrbits_le32(&base->func_en_2, (SERDES_FIFO_FUNC_EN_N | |
| 147 | LS_CLK_DOMAIN_FUNC_EN_N | AUX_FUNC_EN_N)); |
| 148 | return 0; |
| 149 | } |
| 150 | |
| 151 | void s5p_dp_init_aux(struct s5p_dp_device *dp) |
| 152 | { |
| 153 | u32 reg; |
| 154 | struct exynos5_dp *base = dp->base; |
| 155 | |
Martin Roth | 4c3ab73 | 2013-07-08 16:23:54 -0600 | [diff] [blame] | 156 | /* Clear interrupts related to AUX channel */ |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 157 | reg = RPLY_RECEIV | AUX_ERR; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 158 | write32(&base->dp_int_sta, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 159 | |
| 160 | /* Disable AUX channel module */ |
| 161 | setbits_le32(&base->func_en_2, AUX_FUNC_EN_N); |
| 162 | |
| 163 | /* Disable AUX transaction H/W retry */ |
| 164 | reg = (3 & AUX_BIT_PERIOD_MASK) << AUX_BIT_PERIOD_SHIFT; |
| 165 | reg |= (0 & AUX_HW_RETRY_COUNT_MASK) << AUX_HW_RETRY_COUNT_SHIFT; |
| 166 | reg |= (AUX_HW_RETRY_INTERVAL_600_US << AUX_HW_RETRY_INTERVAL_SHIFT); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 167 | write32(&base->aux_hw_retry_ctl, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 168 | |
| 169 | /* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */ |
| 170 | reg = DEFER_CTRL_EN; |
| 171 | reg |= (1 & DEFER_COUNT_MASK) << DEFER_COUNT_SHIFT; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 172 | write32(&base->aux_ch_defer_dtl, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 173 | |
| 174 | /* Enable AUX channel module */ |
| 175 | clrbits_le32(&base->func_en_2, AUX_FUNC_EN_N); |
| 176 | } |
| 177 | |
| 178 | int s5p_dp_start_aux_transaction(struct s5p_dp_device *dp) |
| 179 | { |
| 180 | int reg; |
| 181 | struct exynos5_dp *base = dp->base; |
| 182 | |
| 183 | /* Enable AUX CH operation */ |
| 184 | setbits_le32(&base->aux_ch_ctl_2, AUX_EN); |
| 185 | |
| 186 | /* Is AUX CH command reply received? */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 187 | reg = read32(&base->dp_int_sta); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 188 | while (!(reg & RPLY_RECEIV)) |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 189 | reg = read32(&base->dp_int_sta); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 190 | |
| 191 | /* Clear interrupt source for AUX CH command reply */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 192 | write32(&base->dp_int_sta, RPLY_RECEIV); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 193 | |
| 194 | /* Clear interrupt source for AUX CH access error */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 195 | reg = read32(&base->dp_int_sta); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 196 | if (reg & AUX_ERR) { |
Ronald G. Minnich | 2810afa | 2013-04-18 18:09:24 -0700 | [diff] [blame] | 197 | printk(BIOS_ERR, "%s: AUX_ERR encountered, dp_int_sta: " |
| 198 | "0x%02x\n", __func__, reg); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 199 | write32(&base->dp_int_sta, AUX_ERR); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 200 | return -1; |
| 201 | } |
| 202 | |
| 203 | /* Check AUX CH error access status */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 204 | reg = read32(&base->dp_int_sta); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 205 | if ((reg & AUX_STATUS_MASK) != 0) { |
Ronald G. Minnich | 2810afa | 2013-04-18 18:09:24 -0700 | [diff] [blame] | 206 | printk(BIOS_ERR, "AUX CH error happens: %d\n\n", |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 207 | reg & AUX_STATUS_MASK); |
| 208 | return -1; |
| 209 | } |
| 210 | |
| 211 | return 0; |
| 212 | } |
| 213 | |
| 214 | int s5p_dp_write_byte_to_dpcd(struct s5p_dp_device *dp, |
| 215 | unsigned int reg_addr, |
| 216 | unsigned char data) |
| 217 | { |
| 218 | u32 reg; |
| 219 | int i; |
| 220 | int retval; |
| 221 | struct exynos5_dp *base = dp->base; |
| 222 | |
| 223 | for (i = 0; i < MAX_AUX_RETRY_COUNT; i++) { |
| 224 | /* Clear AUX CH data buffer */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 225 | write32(&base->buf_data_ctl, BUF_CLR); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 226 | |
| 227 | /* Select DPCD device address */ |
| 228 | reg = reg_addr >> AUX_ADDR_7_0_SHIFT; |
| 229 | reg &= AUX_ADDR_7_0_MASK; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 230 | write32(&base->aux_addr_7_0, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 231 | reg = reg_addr >> AUX_ADDR_15_8_SHIFT; |
| 232 | reg &= AUX_ADDR_15_8_MASK; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 233 | write32(&base->aux_addr_15_8, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 234 | reg = reg_addr >> AUX_ADDR_19_16_SHIFT; |
| 235 | reg &= AUX_ADDR_19_16_MASK; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 236 | write32(&base->aux_addr_19_16, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 237 | |
| 238 | /* Write data buffer */ |
| 239 | reg = (unsigned int)data; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 240 | write32(&base->buf_data_0, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 241 | |
| 242 | /* |
| 243 | * Set DisplayPort transaction and write 1 byte |
| 244 | * If bit 3 is 1, DisplayPort transaction. |
| 245 | * If Bit 3 is 0, I2C transaction. |
| 246 | */ |
| 247 | reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 248 | write32(&base->aux_ch_ctl_1, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 249 | |
| 250 | /* Start AUX transaction */ |
| 251 | retval = s5p_dp_start_aux_transaction(dp); |
| 252 | if (retval == 0) |
| 253 | break; |
| 254 | else |
Ronald G. Minnich | 7576f25 | 2013-04-09 14:39:34 -0700 | [diff] [blame] | 255 | printk(BIOS_DEBUG, "Aux Transaction fail!\n"); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 256 | } |
| 257 | |
| 258 | return retval; |
| 259 | } |
| 260 | |
| 261 | int s5p_dp_read_byte_from_dpcd(struct s5p_dp_device *dp, |
| 262 | unsigned int reg_addr, |
| 263 | unsigned char *data) |
| 264 | { |
| 265 | u32 reg; |
| 266 | int i; |
| 267 | int retval; |
| 268 | struct exynos5_dp *base = dp->base; |
| 269 | |
| 270 | for (i = 0; i < MAX_AUX_RETRY_COUNT; i++) { |
| 271 | /* Clear AUX CH data buffer */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 272 | write32(&base->buf_data_ctl, BUF_CLR); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 273 | |
| 274 | /* Select DPCD device address */ |
| 275 | reg = reg_addr >> AUX_ADDR_7_0_SHIFT; |
| 276 | reg &= AUX_ADDR_7_0_MASK; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 277 | write32(&base->aux_addr_7_0, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 278 | reg = reg_addr >> AUX_ADDR_15_8_SHIFT; |
| 279 | reg &= AUX_ADDR_15_8_MASK; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 280 | write32(&base->aux_addr_15_8, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 281 | reg = reg_addr >> AUX_ADDR_19_16_SHIFT; |
| 282 | reg &= AUX_ADDR_19_16_MASK; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 283 | write32(&base->aux_addr_19_16, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 284 | |
| 285 | /* |
| 286 | * Set DisplayPort transaction and read 1 byte |
| 287 | * If bit 3 is 1, DisplayPort transaction. |
| 288 | * If Bit 3 is 0, I2C transaction. |
| 289 | */ |
| 290 | reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 291 | write32(&base->aux_ch_ctl_1, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 292 | |
| 293 | /* Start AUX transaction */ |
| 294 | retval = s5p_dp_start_aux_transaction(dp); |
| 295 | if (retval == 0) |
| 296 | break; |
| 297 | else |
Ronald G. Minnich | 7576f25 | 2013-04-09 14:39:34 -0700 | [diff] [blame] | 298 | printk(BIOS_DEBUG, "Aux Transaction fail!\n"); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 299 | } |
| 300 | |
| 301 | /* Read data buffer */ |
| 302 | if (!retval) { |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 303 | reg = read32(&base->buf_data_0); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 304 | *data = (unsigned char)(reg & 0xff); |
| 305 | } |
| 306 | |
| 307 | return retval; |
| 308 | } |
| 309 | |
| 310 | void s5p_dp_init_video(struct s5p_dp_device *dp) |
| 311 | { |
| 312 | u32 reg; |
| 313 | struct exynos5_dp *base = dp->base; |
| 314 | |
| 315 | reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 316 | write32(&base->common_int_sta_1, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 317 | |
| 318 | reg = 0x0; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 319 | write32(&base->sys_ctl_1, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 320 | |
| 321 | reg = (4 & CHA_CRI_MASK) << CHA_CRI_SHIFT; |
| 322 | reg |= CHA_CTRL; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 323 | write32(&base->sys_ctl_2, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 324 | |
| 325 | reg = 0x0; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 326 | write32(&base->sys_ctl_3, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 327 | } |
| 328 | |
| 329 | void s5p_dp_set_video_color_format(struct s5p_dp_device *dp, |
| 330 | unsigned int color_depth, |
| 331 | unsigned int color_space, |
| 332 | unsigned int dynamic_range, |
| 333 | unsigned int coeff) |
| 334 | { |
| 335 | u32 reg; |
| 336 | struct exynos5_dp *base = dp->base; |
| 337 | |
| 338 | /* Configure the input color depth, color space, dynamic range */ |
| 339 | reg = (dynamic_range << IN_D_RANGE_SHIFT) | |
| 340 | (color_depth << IN_BPC_SHIFT) | |
| 341 | (color_space << IN_COLOR_F_SHIFT); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 342 | write32(&base->video_ctl_2, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 343 | |
| 344 | /* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 345 | reg = read32(&base->video_ctl_3); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 346 | reg &= ~IN_YC_COEFFI_MASK; |
| 347 | if (coeff) |
| 348 | reg |= IN_YC_COEFFI_ITU709; |
| 349 | else |
| 350 | reg |= IN_YC_COEFFI_ITU601; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 351 | write32(&base->video_ctl_3, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 352 | } |
| 353 | |
| 354 | int s5p_dp_is_slave_video_stream_clock_on(struct s5p_dp_device *dp) |
| 355 | { |
| 356 | u32 reg; |
| 357 | struct exynos5_dp *base = dp->base; |
| 358 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 359 | reg = read32(&base->sys_ctl_1); |
| 360 | write32(&base->sys_ctl_1, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 361 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 362 | reg = read32(&base->sys_ctl_1); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 363 | |
| 364 | if (!(reg & DET_STA)) |
| 365 | return -1; |
| 366 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 367 | reg = read32(&base->sys_ctl_2); |
| 368 | write32(&base->sys_ctl_2, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 369 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 370 | reg = read32(&base->sys_ctl_2); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 371 | |
| 372 | if (reg & CHA_STA) { |
Ronald G. Minnich | 7576f25 | 2013-04-09 14:39:34 -0700 | [diff] [blame] | 373 | printk(BIOS_DEBUG, "Input stream clk is changing\n"); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 374 | return -1; |
| 375 | } |
| 376 | |
| 377 | return 0; |
| 378 | } |
| 379 | |
| 380 | void s5p_dp_set_video_cr_mn(struct s5p_dp_device *dp, |
| 381 | enum clock_recovery_m_value_type type, |
| 382 | unsigned int m_value, |
| 383 | unsigned int n_value) |
| 384 | { |
| 385 | u32 reg; |
| 386 | struct exynos5_dp *base = dp->base; |
| 387 | |
| 388 | if (type == REGISTER_M) { |
| 389 | setbits_le32(&base->sys_ctl_4, FIX_M_VID); |
| 390 | |
| 391 | reg = m_value >> M_VID_0_VALUE_SHIFT; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 392 | write32(&base->m_vid_0, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 393 | |
| 394 | reg = (m_value >> M_VID_1_VALUE_SHIFT); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 395 | write32(&base->m_vid_1, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 396 | |
| 397 | reg = (m_value >> M_VID_2_VALUE_SHIFT); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 398 | write32(&base->m_vid_2, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 399 | |
| 400 | reg = n_value >> N_VID_0_VALUE_SHIFT; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 401 | write32(&base->n_vid_0, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 402 | |
| 403 | reg = (n_value >> N_VID_1_VALUE_SHIFT); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 404 | write32(&base->n_vid_1, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 405 | |
| 406 | reg = (n_value >> N_VID_2_VALUE_SHIFT); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 407 | write32(&base->n_vid_2, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 408 | } else { |
| 409 | clrbits_le32(&base->sys_ctl_4, FIX_M_VID); |
| 410 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 411 | write32(&base->n_vid_0, 0x00); |
| 412 | write32(&base->n_vid_1, 0x80); |
| 413 | write32(&base->n_vid_2, 0x00); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 414 | } |
| 415 | } |
| 416 | |
| 417 | void s5p_dp_enable_video_master(struct s5p_dp_device *dp) |
| 418 | { |
| 419 | u32 reg; |
| 420 | struct exynos5_dp *base = dp->base; |
| 421 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 422 | reg = read32(&base->soc_general_ctl); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 423 | reg &= ~VIDEO_MODE_MASK; |
| 424 | reg |= VIDEO_MODE_SLAVE_MODE; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 425 | write32(&base->soc_general_ctl, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 426 | } |
| 427 | |
| 428 | int s5p_dp_is_video_stream_on(struct s5p_dp_device *dp) |
| 429 | { |
| 430 | u32 reg, i = 0; |
Aaron Durbin | 4393346 | 2014-09-24 10:27:29 -0500 | [diff] [blame] | 431 | struct stopwatch sw; |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 432 | struct exynos5_dp *base = dp->base; |
| 433 | |
| 434 | /* Wait for 4 VSYNC_DET interrupts */ |
Aaron Durbin | 4393346 | 2014-09-24 10:27:29 -0500 | [diff] [blame] | 435 | stopwatch_init_msecs_expire(&sw, STREAM_ON_TIMEOUT); |
Gabe Black | 9b764a0 | 2013-07-30 15:11:35 -0700 | [diff] [blame] | 436 | |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 437 | do { |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 438 | reg = read32(&base->common_int_sta_1); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 439 | if (reg & VSYNC_DET) { |
| 440 | i++; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 441 | write32(&base->common_int_sta_1, reg | VSYNC_DET); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 442 | } |
| 443 | if (i == 4) |
| 444 | break; |
Aaron Durbin | 4393346 | 2014-09-24 10:27:29 -0500 | [diff] [blame] | 445 | } while (!stopwatch_expired(&sw)); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 446 | |
| 447 | if (i != 4) { |
Ronald G. Minnich | 7576f25 | 2013-04-09 14:39:34 -0700 | [diff] [blame] | 448 | printk(BIOS_DEBUG, "s5p_dp_is_video_stream_on timeout\n"); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 449 | return -1; |
| 450 | } |
| 451 | |
| 452 | return 0; |
| 453 | } |
| 454 | |
| 455 | void s5p_dp_config_video_slave_mode(struct s5p_dp_device *dp, |
| 456 | struct video_info *video_info) |
| 457 | { |
| 458 | u32 reg; |
| 459 | struct exynos5_dp *base = dp->base; |
| 460 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 461 | reg = read32(&base->func_en_1); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 462 | reg &= ~(MASTER_VID_FUNC_EN_N|SLAVE_VID_FUNC_EN_N); |
| 463 | reg |= MASTER_VID_FUNC_EN_N; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 464 | write32(&base->func_en_1, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 465 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 466 | reg = read32(&base->video_ctl_10); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 467 | reg &= ~INTERACE_SCAN_CFG; |
| 468 | reg |= (video_info->interlaced << 2); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 469 | write32(&base->video_ctl_10, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 470 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 471 | reg = read32(&base->video_ctl_10); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 472 | reg &= ~VSYNC_POLARITY_CFG; |
| 473 | reg |= (video_info->v_sync_polarity << 1); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 474 | write32(&base->video_ctl_10, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 475 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 476 | reg = read32(&base->video_ctl_10); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 477 | reg &= ~HSYNC_POLARITY_CFG; |
| 478 | reg |= (video_info->h_sync_polarity << 0); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 479 | write32(&base->video_ctl_10, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 480 | |
| 481 | reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 482 | write32(&base->soc_general_ctl, reg); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 483 | } |
| 484 | |
| 485 | void s5p_dp_wait_hw_link_training_done(struct s5p_dp_device *dp) |
| 486 | { |
| 487 | u32 reg; |
| 488 | struct exynos5_dp *base = dp->base; |
| 489 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 490 | reg = read32(&base->dp_hw_link_training); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 491 | while (reg & HW_TRAINING_EN) |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 492 | reg = read32(&base->dp_hw_link_training); |
Ronald G. Minnich | 6bde149 | 2013-03-01 10:18:14 -0800 | [diff] [blame] | 493 | } |