108a7aa1eSSimon Glass /* 208a7aa1eSSimon Glass * Copyright (C) 2012 Samsung Electronics 308a7aa1eSSimon Glass * 408a7aa1eSSimon Glass * Author: Donghwa Lee <dh09.lee@samsung.com> 508a7aa1eSSimon Glass * 608a7aa1eSSimon Glass * SPDX-License-Identifier: GPL-2.0+ 708a7aa1eSSimon Glass */ 808a7aa1eSSimon Glass 908a7aa1eSSimon Glass #include <config.h> 1008a7aa1eSSimon Glass #include <common.h> 1108a7aa1eSSimon Glass #include <linux/err.h> 1208a7aa1eSSimon Glass #include <asm/arch/cpu.h> 1308a7aa1eSSimon Glass #include <asm/arch/dp_info.h> 1408a7aa1eSSimon Glass #include <asm/arch/dp.h> 1508a7aa1eSSimon Glass #include <fdtdec.h> 1608a7aa1eSSimon Glass #include <libfdt.h> 17*8c9b8dc0SSimon Glass #include "exynos_dp_lowlevel.h" 1808a7aa1eSSimon Glass 1908a7aa1eSSimon Glass /* Declare global data pointer */ 2008a7aa1eSSimon Glass DECLARE_GLOBAL_DATA_PTR; 2108a7aa1eSSimon Glass 22*8c9b8dc0SSimon Glass static void exynos_dp_enable_video_input(struct exynos_dp *dp_regs, 23*8c9b8dc0SSimon Glass unsigned int enable) 2408a7aa1eSSimon Glass { 2508a7aa1eSSimon Glass unsigned int reg; 2608a7aa1eSSimon Glass 2708a7aa1eSSimon Glass reg = readl(&dp_regs->video_ctl1); 2808a7aa1eSSimon Glass reg &= ~VIDEO_EN_MASK; 2908a7aa1eSSimon Glass 3008a7aa1eSSimon Glass /* enable video input */ 3108a7aa1eSSimon Glass if (enable) 3208a7aa1eSSimon Glass reg |= VIDEO_EN_MASK; 3308a7aa1eSSimon Glass 3408a7aa1eSSimon Glass writel(reg, &dp_regs->video_ctl1); 3508a7aa1eSSimon Glass 3608a7aa1eSSimon Glass return; 3708a7aa1eSSimon Glass } 3808a7aa1eSSimon Glass 39*8c9b8dc0SSimon Glass void exynos_dp_enable_video_bist(struct exynos_dp *dp_regs, unsigned int enable) 4008a7aa1eSSimon Glass { 4108a7aa1eSSimon Glass /* enable video bist */ 4208a7aa1eSSimon Glass unsigned int reg; 4308a7aa1eSSimon Glass 4408a7aa1eSSimon Glass reg = readl(&dp_regs->video_ctl4); 4508a7aa1eSSimon Glass reg &= ~VIDEO_BIST_MASK; 4608a7aa1eSSimon Glass 4708a7aa1eSSimon Glass /* enable video bist */ 4808a7aa1eSSimon Glass if (enable) 4908a7aa1eSSimon Glass reg |= VIDEO_BIST_MASK; 5008a7aa1eSSimon Glass 5108a7aa1eSSimon Glass writel(reg, &dp_regs->video_ctl4); 5208a7aa1eSSimon Glass 5308a7aa1eSSimon Glass return; 5408a7aa1eSSimon Glass } 5508a7aa1eSSimon Glass 56*8c9b8dc0SSimon Glass void exynos_dp_enable_video_mute(struct exynos_dp *dp_regs, unsigned int enable) 5708a7aa1eSSimon Glass { 5808a7aa1eSSimon Glass unsigned int reg; 5908a7aa1eSSimon Glass 6008a7aa1eSSimon Glass reg = readl(&dp_regs->video_ctl1); 6108a7aa1eSSimon Glass reg &= ~(VIDEO_MUTE_MASK); 6208a7aa1eSSimon Glass if (enable) 6308a7aa1eSSimon Glass reg |= VIDEO_MUTE_MASK; 6408a7aa1eSSimon Glass 6508a7aa1eSSimon Glass writel(reg, &dp_regs->video_ctl1); 6608a7aa1eSSimon Glass 6708a7aa1eSSimon Glass return; 6808a7aa1eSSimon Glass } 6908a7aa1eSSimon Glass 7008a7aa1eSSimon Glass 71*8c9b8dc0SSimon Glass static void exynos_dp_init_analog_param(struct exynos_dp *dp_regs) 7208a7aa1eSSimon Glass { 7308a7aa1eSSimon Glass unsigned int reg; 7408a7aa1eSSimon Glass 7508a7aa1eSSimon Glass /* 7608a7aa1eSSimon Glass * Set termination 7708a7aa1eSSimon Glass * Normal bandgap, Normal swing, Tx terminal registor 61 ohm 7808a7aa1eSSimon Glass * 24M Phy clock, TX digital logic power is 100:1.0625V 7908a7aa1eSSimon Glass */ 8008a7aa1eSSimon Glass reg = SEL_BG_NEW_BANDGAP | TX_TERMINAL_CTRL_61_OHM | 8108a7aa1eSSimon Glass SWING_A_30PER_G_NORMAL; 8208a7aa1eSSimon Glass writel(reg, &dp_regs->analog_ctl1); 8308a7aa1eSSimon Glass 8408a7aa1eSSimon Glass reg = SEL_24M | TX_DVDD_BIT_1_0625V; 8508a7aa1eSSimon Glass writel(reg, &dp_regs->analog_ctl2); 8608a7aa1eSSimon Glass 8708a7aa1eSSimon Glass /* 8808a7aa1eSSimon Glass * Set power source for internal clk driver to 1.0625v. 8908a7aa1eSSimon Glass * Select current reference of TX driver current to 00:Ipp/2+Ic/2. 9008a7aa1eSSimon Glass * Set VCO range of PLL +- 0uA 9108a7aa1eSSimon Glass */ 9208a7aa1eSSimon Glass reg = DRIVE_DVDD_BIT_1_0625V | SEL_CURRENT_DEFAULT | VCO_BIT_000_MICRO; 9308a7aa1eSSimon Glass writel(reg, &dp_regs->analog_ctl3); 9408a7aa1eSSimon Glass 9508a7aa1eSSimon Glass /* 9608a7aa1eSSimon Glass * Set AUX TX terminal resistor to 102 ohm 9708a7aa1eSSimon Glass * Set AUX channel amplitude control 9808a7aa1eSSimon Glass */ 9908a7aa1eSSimon Glass reg = PD_RING_OSC | AUX_TERMINAL_CTRL_52_OHM | TX_CUR1_2X | TX_CUR_4_MA; 10008a7aa1eSSimon Glass writel(reg, &dp_regs->pll_filter_ctl1); 10108a7aa1eSSimon Glass 10208a7aa1eSSimon Glass /* 10308a7aa1eSSimon Glass * PLL loop filter bandwidth 10408a7aa1eSSimon Glass * For 2.7Gbps: 175KHz, For 1.62Gbps: 234KHz 10508a7aa1eSSimon Glass * PLL digital power select: 1.2500V 10608a7aa1eSSimon Glass */ 10708a7aa1eSSimon Glass reg = CH3_AMP_0_MV | CH2_AMP_0_MV | CH1_AMP_0_MV | CH0_AMP_0_MV; 10808a7aa1eSSimon Glass 10908a7aa1eSSimon Glass writel(reg, &dp_regs->amp_tuning_ctl); 11008a7aa1eSSimon Glass 11108a7aa1eSSimon Glass /* 11208a7aa1eSSimon Glass * PLL loop filter bandwidth 11308a7aa1eSSimon Glass * For 2.7Gbps: 175KHz, For 1.62Gbps: 234KHz 11408a7aa1eSSimon Glass * PLL digital power select: 1.1250V 11508a7aa1eSSimon Glass */ 11608a7aa1eSSimon Glass reg = DP_PLL_LOOP_BIT_DEFAULT | DP_PLL_REF_BIT_1_1250V; 11708a7aa1eSSimon Glass writel(reg, &dp_regs->pll_ctl); 11808a7aa1eSSimon Glass } 11908a7aa1eSSimon Glass 120*8c9b8dc0SSimon Glass static void exynos_dp_init_interrupt(struct exynos_dp *dp_regs) 12108a7aa1eSSimon Glass { 12208a7aa1eSSimon Glass /* Set interrupt registers to initial states */ 12308a7aa1eSSimon Glass 12408a7aa1eSSimon Glass /* 12508a7aa1eSSimon Glass * Disable interrupt 12608a7aa1eSSimon Glass * INT pin assertion polarity. It must be configured 12708a7aa1eSSimon Glass * correctly according to ICU setting. 12808a7aa1eSSimon Glass * 1 = assert high, 0 = assert low 12908a7aa1eSSimon Glass */ 13008a7aa1eSSimon Glass writel(INT_POL, &dp_regs->int_ctl); 13108a7aa1eSSimon Glass 13208a7aa1eSSimon Glass /* Clear pending registers */ 13308a7aa1eSSimon Glass writel(0xff, &dp_regs->common_int_sta1); 13408a7aa1eSSimon Glass writel(0xff, &dp_regs->common_int_sta2); 13508a7aa1eSSimon Glass writel(0xff, &dp_regs->common_int_sta3); 13608a7aa1eSSimon Glass writel(0xff, &dp_regs->common_int_sta4); 13708a7aa1eSSimon Glass writel(0xff, &dp_regs->int_sta); 13808a7aa1eSSimon Glass 13908a7aa1eSSimon Glass /* 0:mask,1: unmask */ 14008a7aa1eSSimon Glass writel(0x00, &dp_regs->int_sta_mask1); 14108a7aa1eSSimon Glass writel(0x00, &dp_regs->int_sta_mask2); 14208a7aa1eSSimon Glass writel(0x00, &dp_regs->int_sta_mask3); 14308a7aa1eSSimon Glass writel(0x00, &dp_regs->int_sta_mask4); 14408a7aa1eSSimon Glass writel(0x00, &dp_regs->int_sta_mask); 14508a7aa1eSSimon Glass } 14608a7aa1eSSimon Glass 147*8c9b8dc0SSimon Glass void exynos_dp_reset(struct exynos_dp *dp_regs) 14808a7aa1eSSimon Glass { 14908a7aa1eSSimon Glass unsigned int reg_func_1; 15008a7aa1eSSimon Glass 15108a7aa1eSSimon Glass /* dp tx sw reset */ 15208a7aa1eSSimon Glass writel(RESET_DP_TX, &dp_regs->tx_sw_reset); 15308a7aa1eSSimon Glass 154*8c9b8dc0SSimon Glass exynos_dp_enable_video_input(dp_regs, DP_DISABLE); 155*8c9b8dc0SSimon Glass exynos_dp_enable_video_bist(dp_regs, DP_DISABLE); 156*8c9b8dc0SSimon Glass exynos_dp_enable_video_mute(dp_regs, DP_DISABLE); 15708a7aa1eSSimon Glass 15808a7aa1eSSimon Glass /* software reset */ 15908a7aa1eSSimon Glass reg_func_1 = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N | 16008a7aa1eSSimon Glass AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N | 16108a7aa1eSSimon Glass HDCP_FUNC_EN_N | SW_FUNC_EN_N; 16208a7aa1eSSimon Glass 16308a7aa1eSSimon Glass writel(reg_func_1, &dp_regs->func_en1); 16408a7aa1eSSimon Glass writel(reg_func_1, &dp_regs->func_en2); 16508a7aa1eSSimon Glass 16608a7aa1eSSimon Glass mdelay(1); 16708a7aa1eSSimon Glass 168*8c9b8dc0SSimon Glass exynos_dp_init_analog_param(dp_regs); 169*8c9b8dc0SSimon Glass exynos_dp_init_interrupt(dp_regs); 17008a7aa1eSSimon Glass 17108a7aa1eSSimon Glass return; 17208a7aa1eSSimon Glass } 17308a7aa1eSSimon Glass 174*8c9b8dc0SSimon Glass void exynos_dp_enable_sw_func(struct exynos_dp *dp_regs, unsigned int enable) 17508a7aa1eSSimon Glass { 17608a7aa1eSSimon Glass unsigned int reg; 17708a7aa1eSSimon Glass 17808a7aa1eSSimon Glass reg = readl(&dp_regs->func_en1); 17908a7aa1eSSimon Glass reg &= ~(SW_FUNC_EN_N); 18008a7aa1eSSimon Glass 18108a7aa1eSSimon Glass if (!enable) 18208a7aa1eSSimon Glass reg |= SW_FUNC_EN_N; 18308a7aa1eSSimon Glass 18408a7aa1eSSimon Glass writel(reg, &dp_regs->func_en1); 18508a7aa1eSSimon Glass 18608a7aa1eSSimon Glass return; 18708a7aa1eSSimon Glass } 18808a7aa1eSSimon Glass 189*8c9b8dc0SSimon Glass unsigned int exynos_dp_set_analog_power_down(struct exynos_dp *dp_regs, 190*8c9b8dc0SSimon Glass unsigned int block, u32 enable) 19108a7aa1eSSimon Glass { 19208a7aa1eSSimon Glass unsigned int reg; 19308a7aa1eSSimon Glass 19408a7aa1eSSimon Glass reg = readl(&dp_regs->phy_pd); 19508a7aa1eSSimon Glass switch (block) { 19608a7aa1eSSimon Glass case AUX_BLOCK: 19708a7aa1eSSimon Glass reg &= ~(AUX_PD); 19808a7aa1eSSimon Glass if (enable) 19908a7aa1eSSimon Glass reg |= AUX_PD; 20008a7aa1eSSimon Glass break; 20108a7aa1eSSimon Glass case CH0_BLOCK: 20208a7aa1eSSimon Glass reg &= ~(CH0_PD); 20308a7aa1eSSimon Glass if (enable) 20408a7aa1eSSimon Glass reg |= CH0_PD; 20508a7aa1eSSimon Glass break; 20608a7aa1eSSimon Glass case CH1_BLOCK: 20708a7aa1eSSimon Glass reg &= ~(CH1_PD); 20808a7aa1eSSimon Glass if (enable) 20908a7aa1eSSimon Glass reg |= CH1_PD; 21008a7aa1eSSimon Glass break; 21108a7aa1eSSimon Glass case CH2_BLOCK: 21208a7aa1eSSimon Glass reg &= ~(CH2_PD); 21308a7aa1eSSimon Glass if (enable) 21408a7aa1eSSimon Glass reg |= CH2_PD; 21508a7aa1eSSimon Glass break; 21608a7aa1eSSimon Glass case CH3_BLOCK: 21708a7aa1eSSimon Glass reg &= ~(CH3_PD); 21808a7aa1eSSimon Glass if (enable) 21908a7aa1eSSimon Glass reg |= CH3_PD; 22008a7aa1eSSimon Glass break; 22108a7aa1eSSimon Glass case ANALOG_TOTAL: 22208a7aa1eSSimon Glass reg &= ~PHY_PD; 22308a7aa1eSSimon Glass if (enable) 22408a7aa1eSSimon Glass reg |= PHY_PD; 22508a7aa1eSSimon Glass break; 22608a7aa1eSSimon Glass case POWER_ALL: 22708a7aa1eSSimon Glass reg &= ~(PHY_PD | AUX_PD | CH0_PD | CH1_PD | CH2_PD | 22808a7aa1eSSimon Glass CH3_PD); 22908a7aa1eSSimon Glass if (enable) 23008a7aa1eSSimon Glass reg |= (PHY_PD | AUX_PD | CH0_PD | CH1_PD | 23108a7aa1eSSimon Glass CH2_PD | CH3_PD); 23208a7aa1eSSimon Glass break; 23308a7aa1eSSimon Glass default: 23408a7aa1eSSimon Glass printf("DP undefined block number : %d\n", block); 23508a7aa1eSSimon Glass return -1; 23608a7aa1eSSimon Glass } 23708a7aa1eSSimon Glass 23808a7aa1eSSimon Glass writel(reg, &dp_regs->phy_pd); 23908a7aa1eSSimon Glass 24008a7aa1eSSimon Glass return 0; 24108a7aa1eSSimon Glass } 24208a7aa1eSSimon Glass 243*8c9b8dc0SSimon Glass unsigned int exynos_dp_get_pll_lock_status(struct exynos_dp *dp_regs) 24408a7aa1eSSimon Glass { 24508a7aa1eSSimon Glass unsigned int reg; 24608a7aa1eSSimon Glass 24708a7aa1eSSimon Glass reg = readl(&dp_regs->debug_ctl); 24808a7aa1eSSimon Glass 24908a7aa1eSSimon Glass if (reg & PLL_LOCK) 25008a7aa1eSSimon Glass return PLL_LOCKED; 25108a7aa1eSSimon Glass else 25208a7aa1eSSimon Glass return PLL_UNLOCKED; 25308a7aa1eSSimon Glass } 25408a7aa1eSSimon Glass 255*8c9b8dc0SSimon Glass static void exynos_dp_set_pll_power(struct exynos_dp *dp_regs, 256*8c9b8dc0SSimon Glass unsigned int enable) 25708a7aa1eSSimon Glass { 25808a7aa1eSSimon Glass unsigned int reg; 25908a7aa1eSSimon Glass 26008a7aa1eSSimon Glass reg = readl(&dp_regs->pll_ctl); 26108a7aa1eSSimon Glass reg &= ~(DP_PLL_PD); 26208a7aa1eSSimon Glass 26308a7aa1eSSimon Glass if (!enable) 26408a7aa1eSSimon Glass reg |= DP_PLL_PD; 26508a7aa1eSSimon Glass 26608a7aa1eSSimon Glass writel(reg, &dp_regs->pll_ctl); 26708a7aa1eSSimon Glass } 26808a7aa1eSSimon Glass 269*8c9b8dc0SSimon Glass int exynos_dp_init_analog_func(struct exynos_dp *dp_regs) 27008a7aa1eSSimon Glass { 27108a7aa1eSSimon Glass int ret = EXYNOS_DP_SUCCESS; 27208a7aa1eSSimon Glass unsigned int retry_cnt = 10; 27308a7aa1eSSimon Glass unsigned int reg; 27408a7aa1eSSimon Glass 27508a7aa1eSSimon Glass /* Power On All Analog block */ 276*8c9b8dc0SSimon Glass exynos_dp_set_analog_power_down(dp_regs, POWER_ALL, DP_DISABLE); 27708a7aa1eSSimon Glass 27808a7aa1eSSimon Glass reg = PLL_LOCK_CHG; 27908a7aa1eSSimon Glass writel(reg, &dp_regs->common_int_sta1); 28008a7aa1eSSimon Glass 28108a7aa1eSSimon Glass reg = readl(&dp_regs->debug_ctl); 28208a7aa1eSSimon Glass reg &= ~(F_PLL_LOCK | PLL_LOCK_CTRL); 28308a7aa1eSSimon Glass writel(reg, &dp_regs->debug_ctl); 28408a7aa1eSSimon Glass 28508a7aa1eSSimon Glass /* Assert DP PLL Reset */ 28608a7aa1eSSimon Glass reg = readl(&dp_regs->pll_ctl); 28708a7aa1eSSimon Glass reg |= DP_PLL_RESET; 28808a7aa1eSSimon Glass writel(reg, &dp_regs->pll_ctl); 28908a7aa1eSSimon Glass 29008a7aa1eSSimon Glass mdelay(1); 29108a7aa1eSSimon Glass 29208a7aa1eSSimon Glass /* Deassert DP PLL Reset */ 29308a7aa1eSSimon Glass reg = readl(&dp_regs->pll_ctl); 29408a7aa1eSSimon Glass reg &= ~(DP_PLL_RESET); 29508a7aa1eSSimon Glass writel(reg, &dp_regs->pll_ctl); 29608a7aa1eSSimon Glass 297*8c9b8dc0SSimon Glass exynos_dp_set_pll_power(dp_regs, DP_ENABLE); 29808a7aa1eSSimon Glass 299*8c9b8dc0SSimon Glass while (exynos_dp_get_pll_lock_status(dp_regs) == PLL_UNLOCKED) { 30008a7aa1eSSimon Glass mdelay(1); 30108a7aa1eSSimon Glass retry_cnt--; 30208a7aa1eSSimon Glass if (retry_cnt == 0) { 30308a7aa1eSSimon Glass printf("DP dp's pll lock failed : retry : %d\n", 30408a7aa1eSSimon Glass retry_cnt); 30508a7aa1eSSimon Glass return -EINVAL; 30608a7aa1eSSimon Glass } 30708a7aa1eSSimon Glass } 30808a7aa1eSSimon Glass 30908a7aa1eSSimon Glass debug("dp's pll lock success(%d)\n", retry_cnt); 31008a7aa1eSSimon Glass 31108a7aa1eSSimon Glass /* Enable Serdes FIFO function and Link symbol clock domain module */ 31208a7aa1eSSimon Glass reg = readl(&dp_regs->func_en2); 31308a7aa1eSSimon Glass reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N 31408a7aa1eSSimon Glass | AUX_FUNC_EN_N); 31508a7aa1eSSimon Glass writel(reg, &dp_regs->func_en2); 31608a7aa1eSSimon Glass 31708a7aa1eSSimon Glass return ret; 31808a7aa1eSSimon Glass } 31908a7aa1eSSimon Glass 320*8c9b8dc0SSimon Glass void exynos_dp_init_hpd(struct exynos_dp *dp_regs) 32108a7aa1eSSimon Glass { 32208a7aa1eSSimon Glass unsigned int reg; 32308a7aa1eSSimon Glass 32408a7aa1eSSimon Glass /* Clear interrupts related to Hot Plug Detect */ 32508a7aa1eSSimon Glass reg = HOTPLUG_CHG | HPD_LOST | PLUG; 32608a7aa1eSSimon Glass writel(reg, &dp_regs->common_int_sta4); 32708a7aa1eSSimon Glass 32808a7aa1eSSimon Glass reg = INT_HPD; 32908a7aa1eSSimon Glass writel(reg, &dp_regs->int_sta); 33008a7aa1eSSimon Glass 33108a7aa1eSSimon Glass reg = readl(&dp_regs->sys_ctl3); 33208a7aa1eSSimon Glass reg &= ~(F_HPD | HPD_CTRL); 33308a7aa1eSSimon Glass writel(reg, &dp_regs->sys_ctl3); 33408a7aa1eSSimon Glass 33508a7aa1eSSimon Glass return; 33608a7aa1eSSimon Glass } 33708a7aa1eSSimon Glass 338*8c9b8dc0SSimon Glass static inline void exynos_dp_reset_aux(struct exynos_dp *dp_regs) 33908a7aa1eSSimon Glass { 34008a7aa1eSSimon Glass unsigned int reg; 34108a7aa1eSSimon Glass 34208a7aa1eSSimon Glass /* Disable AUX channel module */ 34308a7aa1eSSimon Glass reg = readl(&dp_regs->func_en2); 34408a7aa1eSSimon Glass reg |= AUX_FUNC_EN_N; 34508a7aa1eSSimon Glass writel(reg, &dp_regs->func_en2); 34608a7aa1eSSimon Glass 34708a7aa1eSSimon Glass return; 34808a7aa1eSSimon Glass } 34908a7aa1eSSimon Glass 350*8c9b8dc0SSimon Glass void exynos_dp_init_aux(struct exynos_dp *dp_regs) 35108a7aa1eSSimon Glass { 35208a7aa1eSSimon Glass unsigned int reg; 35308a7aa1eSSimon Glass 35408a7aa1eSSimon Glass /* Clear interrupts related to AUX channel */ 35508a7aa1eSSimon Glass reg = RPLY_RECEIV | AUX_ERR; 35608a7aa1eSSimon Glass writel(reg, &dp_regs->int_sta); 35708a7aa1eSSimon Glass 358*8c9b8dc0SSimon Glass exynos_dp_reset_aux(dp_regs); 35908a7aa1eSSimon Glass 36008a7aa1eSSimon Glass /* Disable AUX transaction H/W retry */ 36108a7aa1eSSimon Glass reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) | AUX_HW_RETRY_COUNT_SEL(3)| 36208a7aa1eSSimon Glass AUX_HW_RETRY_INTERVAL_600_MICROSECONDS; 36308a7aa1eSSimon Glass writel(reg, &dp_regs->aux_hw_retry_ctl); 36408a7aa1eSSimon Glass 36508a7aa1eSSimon Glass /* Receive AUX Channel DEFER commands equal to DEFER_COUNT*64 */ 36608a7aa1eSSimon Glass reg = DEFER_CTRL_EN | DEFER_COUNT(1); 36708a7aa1eSSimon Glass writel(reg, &dp_regs->aux_ch_defer_ctl); 36808a7aa1eSSimon Glass 36908a7aa1eSSimon Glass /* Enable AUX channel module */ 37008a7aa1eSSimon Glass reg = readl(&dp_regs->func_en2); 37108a7aa1eSSimon Glass reg &= ~AUX_FUNC_EN_N; 37208a7aa1eSSimon Glass writel(reg, &dp_regs->func_en2); 37308a7aa1eSSimon Glass 37408a7aa1eSSimon Glass return; 37508a7aa1eSSimon Glass } 37608a7aa1eSSimon Glass 377*8c9b8dc0SSimon Glass void exynos_dp_config_interrupt(struct exynos_dp *dp_regs) 37808a7aa1eSSimon Glass { 37908a7aa1eSSimon Glass unsigned int reg; 38008a7aa1eSSimon Glass 38108a7aa1eSSimon Glass /* 0: mask, 1: unmask */ 38208a7aa1eSSimon Glass reg = COMMON_INT_MASK_1; 38308a7aa1eSSimon Glass writel(reg, &dp_regs->common_int_mask1); 38408a7aa1eSSimon Glass 38508a7aa1eSSimon Glass reg = COMMON_INT_MASK_2; 38608a7aa1eSSimon Glass writel(reg, &dp_regs->common_int_mask2); 38708a7aa1eSSimon Glass 38808a7aa1eSSimon Glass reg = COMMON_INT_MASK_3; 38908a7aa1eSSimon Glass writel(reg, &dp_regs->common_int_mask3); 39008a7aa1eSSimon Glass 39108a7aa1eSSimon Glass reg = COMMON_INT_MASK_4; 39208a7aa1eSSimon Glass writel(reg, &dp_regs->common_int_mask4); 39308a7aa1eSSimon Glass 39408a7aa1eSSimon Glass reg = INT_STA_MASK; 39508a7aa1eSSimon Glass writel(reg, &dp_regs->int_sta_mask); 39608a7aa1eSSimon Glass 39708a7aa1eSSimon Glass return; 39808a7aa1eSSimon Glass } 39908a7aa1eSSimon Glass 400*8c9b8dc0SSimon Glass unsigned int exynos_dp_get_plug_in_status(struct exynos_dp *dp_regs) 40108a7aa1eSSimon Glass { 40208a7aa1eSSimon Glass unsigned int reg; 40308a7aa1eSSimon Glass 40408a7aa1eSSimon Glass reg = readl(&dp_regs->sys_ctl3); 40508a7aa1eSSimon Glass if (reg & HPD_STATUS) 40608a7aa1eSSimon Glass return 0; 40708a7aa1eSSimon Glass 40808a7aa1eSSimon Glass return -1; 40908a7aa1eSSimon Glass } 41008a7aa1eSSimon Glass 411*8c9b8dc0SSimon Glass unsigned int exynos_dp_detect_hpd(struct exynos_dp *dp_regs) 41208a7aa1eSSimon Glass { 41308a7aa1eSSimon Glass int timeout_loop = DP_TIMEOUT_LOOP_COUNT; 41408a7aa1eSSimon Glass 41508a7aa1eSSimon Glass mdelay(2); 41608a7aa1eSSimon Glass 417*8c9b8dc0SSimon Glass while (exynos_dp_get_plug_in_status(dp_regs) != 0) { 41808a7aa1eSSimon Glass if (timeout_loop == 0) 41908a7aa1eSSimon Glass return -EINVAL; 42008a7aa1eSSimon Glass mdelay(10); 42108a7aa1eSSimon Glass timeout_loop--; 42208a7aa1eSSimon Glass } 42308a7aa1eSSimon Glass 42408a7aa1eSSimon Glass return EXYNOS_DP_SUCCESS; 42508a7aa1eSSimon Glass } 42608a7aa1eSSimon Glass 427*8c9b8dc0SSimon Glass unsigned int exynos_dp_start_aux_transaction(struct exynos_dp *dp_regs) 42808a7aa1eSSimon Glass { 42908a7aa1eSSimon Glass unsigned int reg; 43008a7aa1eSSimon Glass unsigned int ret = 0; 43108a7aa1eSSimon Glass unsigned int retry_cnt; 43208a7aa1eSSimon Glass 43308a7aa1eSSimon Glass /* Enable AUX CH operation */ 43408a7aa1eSSimon Glass reg = readl(&dp_regs->aux_ch_ctl2); 43508a7aa1eSSimon Glass reg |= AUX_EN; 43608a7aa1eSSimon Glass writel(reg, &dp_regs->aux_ch_ctl2); 43708a7aa1eSSimon Glass 43808a7aa1eSSimon Glass retry_cnt = 10; 43908a7aa1eSSimon Glass while (retry_cnt) { 44008a7aa1eSSimon Glass reg = readl(&dp_regs->int_sta); 44108a7aa1eSSimon Glass if (!(reg & RPLY_RECEIV)) { 44208a7aa1eSSimon Glass if (retry_cnt == 0) { 44308a7aa1eSSimon Glass printf("DP Reply Timeout!!\n"); 44408a7aa1eSSimon Glass ret = -EAGAIN; 44508a7aa1eSSimon Glass return ret; 44608a7aa1eSSimon Glass } 44708a7aa1eSSimon Glass mdelay(1); 44808a7aa1eSSimon Glass retry_cnt--; 44908a7aa1eSSimon Glass } else 45008a7aa1eSSimon Glass break; 45108a7aa1eSSimon Glass } 45208a7aa1eSSimon Glass 45308a7aa1eSSimon Glass /* Clear interrupt source for AUX CH command reply */ 45408a7aa1eSSimon Glass writel(reg, &dp_regs->int_sta); 45508a7aa1eSSimon Glass 45608a7aa1eSSimon Glass /* Clear interrupt source for AUX CH access error */ 45708a7aa1eSSimon Glass reg = readl(&dp_regs->int_sta); 45808a7aa1eSSimon Glass if (reg & AUX_ERR) { 45908a7aa1eSSimon Glass printf("DP Aux Access Error\n"); 46008a7aa1eSSimon Glass writel(AUX_ERR, &dp_regs->int_sta); 46108a7aa1eSSimon Glass ret = -EAGAIN; 46208a7aa1eSSimon Glass return ret; 46308a7aa1eSSimon Glass } 46408a7aa1eSSimon Glass 46508a7aa1eSSimon Glass /* Check AUX CH error access status */ 46608a7aa1eSSimon Glass reg = readl(&dp_regs->aux_ch_sta); 46708a7aa1eSSimon Glass if ((reg & AUX_STATUS_MASK) != 0) { 46808a7aa1eSSimon Glass debug("DP AUX CH error happens: %x\n", reg & AUX_STATUS_MASK); 46908a7aa1eSSimon Glass ret = -EAGAIN; 47008a7aa1eSSimon Glass return ret; 47108a7aa1eSSimon Glass } 47208a7aa1eSSimon Glass 47308a7aa1eSSimon Glass return EXYNOS_DP_SUCCESS; 47408a7aa1eSSimon Glass } 47508a7aa1eSSimon Glass 476*8c9b8dc0SSimon Glass unsigned int exynos_dp_write_byte_to_dpcd(struct exynos_dp *dp_regs, 477*8c9b8dc0SSimon Glass unsigned int reg_addr, 47808a7aa1eSSimon Glass unsigned char data) 47908a7aa1eSSimon Glass { 48008a7aa1eSSimon Glass unsigned int reg, ret; 48108a7aa1eSSimon Glass 48208a7aa1eSSimon Glass /* Clear AUX CH data buffer */ 48308a7aa1eSSimon Glass reg = BUF_CLR; 48408a7aa1eSSimon Glass writel(reg, &dp_regs->buffer_data_ctl); 48508a7aa1eSSimon Glass 48608a7aa1eSSimon Glass /* Select DPCD device address */ 48708a7aa1eSSimon Glass reg = AUX_ADDR_7_0(reg_addr); 48808a7aa1eSSimon Glass writel(reg, &dp_regs->aux_addr_7_0); 48908a7aa1eSSimon Glass reg = AUX_ADDR_15_8(reg_addr); 49008a7aa1eSSimon Glass writel(reg, &dp_regs->aux_addr_15_8); 49108a7aa1eSSimon Glass reg = AUX_ADDR_19_16(reg_addr); 49208a7aa1eSSimon Glass writel(reg, &dp_regs->aux_addr_19_16); 49308a7aa1eSSimon Glass 49408a7aa1eSSimon Glass /* Write data buffer */ 49508a7aa1eSSimon Glass reg = (unsigned int)data; 49608a7aa1eSSimon Glass writel(reg, &dp_regs->buf_data0); 49708a7aa1eSSimon Glass 49808a7aa1eSSimon Glass /* 49908a7aa1eSSimon Glass * Set DisplayPort transaction and write 1 byte 50008a7aa1eSSimon Glass * If bit 3 is 1, DisplayPort transaction. 50108a7aa1eSSimon Glass * If Bit 3 is 0, I2C transaction. 50208a7aa1eSSimon Glass */ 50308a7aa1eSSimon Glass reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; 50408a7aa1eSSimon Glass writel(reg, &dp_regs->aux_ch_ctl1); 50508a7aa1eSSimon Glass 50608a7aa1eSSimon Glass /* Start AUX transaction */ 507*8c9b8dc0SSimon Glass ret = exynos_dp_start_aux_transaction(dp_regs); 50808a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 50908a7aa1eSSimon Glass printf("DP Aux transaction failed\n"); 51008a7aa1eSSimon Glass return ret; 51108a7aa1eSSimon Glass } 51208a7aa1eSSimon Glass 51308a7aa1eSSimon Glass return ret; 51408a7aa1eSSimon Glass } 51508a7aa1eSSimon Glass 516*8c9b8dc0SSimon Glass unsigned int exynos_dp_read_byte_from_dpcd(struct exynos_dp *dp_regs, 517*8c9b8dc0SSimon Glass unsigned int reg_addr, 51808a7aa1eSSimon Glass unsigned char *data) 51908a7aa1eSSimon Glass { 52008a7aa1eSSimon Glass unsigned int reg; 52108a7aa1eSSimon Glass int retval; 52208a7aa1eSSimon Glass 52308a7aa1eSSimon Glass /* Clear AUX CH data buffer */ 52408a7aa1eSSimon Glass reg = BUF_CLR; 52508a7aa1eSSimon Glass writel(reg, &dp_regs->buffer_data_ctl); 52608a7aa1eSSimon Glass 52708a7aa1eSSimon Glass /* Select DPCD device address */ 52808a7aa1eSSimon Glass reg = AUX_ADDR_7_0(reg_addr); 52908a7aa1eSSimon Glass writel(reg, &dp_regs->aux_addr_7_0); 53008a7aa1eSSimon Glass reg = AUX_ADDR_15_8(reg_addr); 53108a7aa1eSSimon Glass writel(reg, &dp_regs->aux_addr_15_8); 53208a7aa1eSSimon Glass reg = AUX_ADDR_19_16(reg_addr); 53308a7aa1eSSimon Glass writel(reg, &dp_regs->aux_addr_19_16); 53408a7aa1eSSimon Glass 53508a7aa1eSSimon Glass /* 53608a7aa1eSSimon Glass * Set DisplayPort transaction and read 1 byte 53708a7aa1eSSimon Glass * If bit 3 is 1, DisplayPort transaction. 53808a7aa1eSSimon Glass * If Bit 3 is 0, I2C transaction. 53908a7aa1eSSimon Glass */ 54008a7aa1eSSimon Glass reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; 54108a7aa1eSSimon Glass writel(reg, &dp_regs->aux_ch_ctl1); 54208a7aa1eSSimon Glass 54308a7aa1eSSimon Glass /* Start AUX transaction */ 544*8c9b8dc0SSimon Glass retval = exynos_dp_start_aux_transaction(dp_regs); 54508a7aa1eSSimon Glass if (!retval) 54608a7aa1eSSimon Glass debug("DP Aux Transaction fail!\n"); 54708a7aa1eSSimon Glass 54808a7aa1eSSimon Glass /* Read data buffer */ 54908a7aa1eSSimon Glass reg = readl(&dp_regs->buf_data0); 55008a7aa1eSSimon Glass *data = (unsigned char)(reg & 0xff); 55108a7aa1eSSimon Glass 55208a7aa1eSSimon Glass return retval; 55308a7aa1eSSimon Glass } 55408a7aa1eSSimon Glass 555*8c9b8dc0SSimon Glass unsigned int exynos_dp_write_bytes_to_dpcd(struct exynos_dp *dp_regs, 556*8c9b8dc0SSimon Glass unsigned int reg_addr, 55708a7aa1eSSimon Glass unsigned int count, 55808a7aa1eSSimon Glass unsigned char data[]) 55908a7aa1eSSimon Glass { 56008a7aa1eSSimon Glass unsigned int reg; 56108a7aa1eSSimon Glass unsigned int start_offset; 56208a7aa1eSSimon Glass unsigned int cur_data_count; 56308a7aa1eSSimon Glass unsigned int cur_data_idx; 56408a7aa1eSSimon Glass unsigned int retry_cnt; 56508a7aa1eSSimon Glass unsigned int ret = 0; 56608a7aa1eSSimon Glass 56708a7aa1eSSimon Glass /* Clear AUX CH data buffer */ 56808a7aa1eSSimon Glass reg = BUF_CLR; 56908a7aa1eSSimon Glass writel(reg, &dp_regs->buffer_data_ctl); 57008a7aa1eSSimon Glass 57108a7aa1eSSimon Glass start_offset = 0; 57208a7aa1eSSimon Glass while (start_offset < count) { 57308a7aa1eSSimon Glass /* Buffer size of AUX CH is 16 * 4bytes */ 57408a7aa1eSSimon Glass if ((count - start_offset) > 16) 57508a7aa1eSSimon Glass cur_data_count = 16; 57608a7aa1eSSimon Glass else 57708a7aa1eSSimon Glass cur_data_count = count - start_offset; 57808a7aa1eSSimon Glass 57908a7aa1eSSimon Glass retry_cnt = 5; 58008a7aa1eSSimon Glass while (retry_cnt) { 58108a7aa1eSSimon Glass /* Select DPCD device address */ 58208a7aa1eSSimon Glass reg = AUX_ADDR_7_0(reg_addr + start_offset); 58308a7aa1eSSimon Glass writel(reg, &dp_regs->aux_addr_7_0); 58408a7aa1eSSimon Glass reg = AUX_ADDR_15_8(reg_addr + start_offset); 58508a7aa1eSSimon Glass writel(reg, &dp_regs->aux_addr_15_8); 58608a7aa1eSSimon Glass reg = AUX_ADDR_19_16(reg_addr + start_offset); 58708a7aa1eSSimon Glass writel(reg, &dp_regs->aux_addr_19_16); 58808a7aa1eSSimon Glass 58908a7aa1eSSimon Glass for (cur_data_idx = 0; cur_data_idx < cur_data_count; 59008a7aa1eSSimon Glass cur_data_idx++) { 59108a7aa1eSSimon Glass reg = data[start_offset + cur_data_idx]; 59208a7aa1eSSimon Glass writel(reg, (unsigned int)&dp_regs->buf_data0 + 59308a7aa1eSSimon Glass (4 * cur_data_idx)); 59408a7aa1eSSimon Glass } 59508a7aa1eSSimon Glass /* 59608a7aa1eSSimon Glass * Set DisplayPort transaction and write 59708a7aa1eSSimon Glass * If bit 3 is 1, DisplayPort transaction. 59808a7aa1eSSimon Glass * If Bit 3 is 0, I2C transaction. 59908a7aa1eSSimon Glass */ 60008a7aa1eSSimon Glass reg = AUX_LENGTH(cur_data_count) | 60108a7aa1eSSimon Glass AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; 60208a7aa1eSSimon Glass writel(reg, &dp_regs->aux_ch_ctl1); 60308a7aa1eSSimon Glass 60408a7aa1eSSimon Glass /* Start AUX transaction */ 605*8c9b8dc0SSimon Glass ret = exynos_dp_start_aux_transaction(dp_regs); 60608a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 60708a7aa1eSSimon Glass if (retry_cnt == 0) { 60808a7aa1eSSimon Glass printf("DP Aux Transaction failed\n"); 60908a7aa1eSSimon Glass return ret; 61008a7aa1eSSimon Glass } 61108a7aa1eSSimon Glass retry_cnt--; 61208a7aa1eSSimon Glass } else 61308a7aa1eSSimon Glass break; 61408a7aa1eSSimon Glass } 61508a7aa1eSSimon Glass start_offset += cur_data_count; 61608a7aa1eSSimon Glass } 61708a7aa1eSSimon Glass 61808a7aa1eSSimon Glass return ret; 61908a7aa1eSSimon Glass } 62008a7aa1eSSimon Glass 621*8c9b8dc0SSimon Glass unsigned int exynos_dp_read_bytes_from_dpcd(struct exynos_dp *dp_regs, 622*8c9b8dc0SSimon Glass unsigned int reg_addr, 62308a7aa1eSSimon Glass unsigned int count, 62408a7aa1eSSimon Glass unsigned char data[]) 62508a7aa1eSSimon Glass { 62608a7aa1eSSimon Glass unsigned int reg; 62708a7aa1eSSimon Glass unsigned int start_offset; 62808a7aa1eSSimon Glass unsigned int cur_data_count; 62908a7aa1eSSimon Glass unsigned int cur_data_idx; 63008a7aa1eSSimon Glass unsigned int retry_cnt; 63108a7aa1eSSimon Glass unsigned int ret = 0; 63208a7aa1eSSimon Glass 63308a7aa1eSSimon Glass /* Clear AUX CH data buffer */ 63408a7aa1eSSimon Glass reg = BUF_CLR; 63508a7aa1eSSimon Glass writel(reg, &dp_regs->buffer_data_ctl); 63608a7aa1eSSimon Glass 63708a7aa1eSSimon Glass start_offset = 0; 63808a7aa1eSSimon Glass while (start_offset < count) { 63908a7aa1eSSimon Glass /* Buffer size of AUX CH is 16 * 4bytes */ 64008a7aa1eSSimon Glass if ((count - start_offset) > 16) 64108a7aa1eSSimon Glass cur_data_count = 16; 64208a7aa1eSSimon Glass else 64308a7aa1eSSimon Glass cur_data_count = count - start_offset; 64408a7aa1eSSimon Glass 64508a7aa1eSSimon Glass retry_cnt = 5; 64608a7aa1eSSimon Glass while (retry_cnt) { 64708a7aa1eSSimon Glass /* Select DPCD device address */ 64808a7aa1eSSimon Glass reg = AUX_ADDR_7_0(reg_addr + start_offset); 64908a7aa1eSSimon Glass writel(reg, &dp_regs->aux_addr_7_0); 65008a7aa1eSSimon Glass reg = AUX_ADDR_15_8(reg_addr + start_offset); 65108a7aa1eSSimon Glass writel(reg, &dp_regs->aux_addr_15_8); 65208a7aa1eSSimon Glass reg = AUX_ADDR_19_16(reg_addr + start_offset); 65308a7aa1eSSimon Glass writel(reg, &dp_regs->aux_addr_19_16); 65408a7aa1eSSimon Glass /* 65508a7aa1eSSimon Glass * Set DisplayPort transaction and read 65608a7aa1eSSimon Glass * If bit 3 is 1, DisplayPort transaction. 65708a7aa1eSSimon Glass * If Bit 3 is 0, I2C transaction. 65808a7aa1eSSimon Glass */ 65908a7aa1eSSimon Glass reg = AUX_LENGTH(cur_data_count) | 66008a7aa1eSSimon Glass AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; 66108a7aa1eSSimon Glass writel(reg, &dp_regs->aux_ch_ctl1); 66208a7aa1eSSimon Glass 66308a7aa1eSSimon Glass /* Start AUX transaction */ 664*8c9b8dc0SSimon Glass ret = exynos_dp_start_aux_transaction(dp_regs); 66508a7aa1eSSimon Glass if (ret != EXYNOS_DP_SUCCESS) { 66608a7aa1eSSimon Glass if (retry_cnt == 0) { 66708a7aa1eSSimon Glass printf("DP Aux Transaction failed\n"); 66808a7aa1eSSimon Glass return ret; 66908a7aa1eSSimon Glass } 67008a7aa1eSSimon Glass retry_cnt--; 67108a7aa1eSSimon Glass } else 67208a7aa1eSSimon Glass break; 67308a7aa1eSSimon Glass } 67408a7aa1eSSimon Glass 67508a7aa1eSSimon Glass for (cur_data_idx = 0; cur_data_idx < cur_data_count; 67608a7aa1eSSimon Glass cur_data_idx++) { 67708a7aa1eSSimon Glass reg = readl((unsigned int)&dp_regs->buf_data0 + 67808a7aa1eSSimon Glass 4 * cur_data_idx); 67908a7aa1eSSimon Glass data[start_offset + cur_data_idx] = (unsigned char)reg; 68008a7aa1eSSimon Glass } 68108a7aa1eSSimon Glass 68208a7aa1eSSimon Glass start_offset += cur_data_count; 68308a7aa1eSSimon Glass } 68408a7aa1eSSimon Glass 68508a7aa1eSSimon Glass return ret; 68608a7aa1eSSimon Glass } 68708a7aa1eSSimon Glass 688*8c9b8dc0SSimon Glass int exynos_dp_select_i2c_device(struct exynos_dp *dp_regs, 689*8c9b8dc0SSimon Glass unsigned int device_addr, unsigned int reg_addr) 69008a7aa1eSSimon Glass { 69108a7aa1eSSimon Glass unsigned int reg; 69208a7aa1eSSimon Glass int retval; 69308a7aa1eSSimon Glass 69408a7aa1eSSimon Glass /* Set EDID device address */ 69508a7aa1eSSimon Glass reg = device_addr; 69608a7aa1eSSimon Glass writel(reg, &dp_regs->aux_addr_7_0); 69708a7aa1eSSimon Glass writel(0x0, &dp_regs->aux_addr_15_8); 69808a7aa1eSSimon Glass writel(0x0, &dp_regs->aux_addr_19_16); 69908a7aa1eSSimon Glass 70008a7aa1eSSimon Glass /* Set offset from base address of EDID device */ 70108a7aa1eSSimon Glass writel(reg_addr, &dp_regs->buf_data0); 70208a7aa1eSSimon Glass 70308a7aa1eSSimon Glass /* 70408a7aa1eSSimon Glass * Set I2C transaction and write address 70508a7aa1eSSimon Glass * If bit 3 is 1, DisplayPort transaction. 70608a7aa1eSSimon Glass * If Bit 3 is 0, I2C transaction. 70708a7aa1eSSimon Glass */ 70808a7aa1eSSimon Glass reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT | 70908a7aa1eSSimon Glass AUX_TX_COMM_WRITE; 71008a7aa1eSSimon Glass writel(reg, &dp_regs->aux_ch_ctl1); 71108a7aa1eSSimon Glass 71208a7aa1eSSimon Glass /* Start AUX transaction */ 713*8c9b8dc0SSimon Glass retval = exynos_dp_start_aux_transaction(dp_regs); 71408a7aa1eSSimon Glass if (retval != 0) 71508a7aa1eSSimon Glass printf("%s: DP Aux Transaction fail!\n", __func__); 71608a7aa1eSSimon Glass 71708a7aa1eSSimon Glass return retval; 71808a7aa1eSSimon Glass } 71908a7aa1eSSimon Glass 720*8c9b8dc0SSimon Glass int exynos_dp_read_byte_from_i2c(struct exynos_dp *dp_regs, 721*8c9b8dc0SSimon Glass unsigned int device_addr, 722*8c9b8dc0SSimon Glass unsigned int reg_addr, unsigned int *data) 72308a7aa1eSSimon Glass { 72408a7aa1eSSimon Glass unsigned int reg; 72508a7aa1eSSimon Glass int i; 72608a7aa1eSSimon Glass int retval; 72708a7aa1eSSimon Glass 72808a7aa1eSSimon Glass for (i = 0; i < 10; i++) { 72908a7aa1eSSimon Glass /* Clear AUX CH data buffer */ 73008a7aa1eSSimon Glass reg = BUF_CLR; 73108a7aa1eSSimon Glass writel(reg, &dp_regs->buffer_data_ctl); 73208a7aa1eSSimon Glass 73308a7aa1eSSimon Glass /* Select EDID device */ 734*8c9b8dc0SSimon Glass retval = exynos_dp_select_i2c_device(dp_regs, device_addr, 735*8c9b8dc0SSimon Glass reg_addr); 73608a7aa1eSSimon Glass if (retval != 0) { 73708a7aa1eSSimon Glass printf("DP Select EDID device fail. retry !\n"); 73808a7aa1eSSimon Glass continue; 73908a7aa1eSSimon Glass } 74008a7aa1eSSimon Glass 74108a7aa1eSSimon Glass /* 74208a7aa1eSSimon Glass * Set I2C transaction and read data 74308a7aa1eSSimon Glass * If bit 3 is 1, DisplayPort transaction. 74408a7aa1eSSimon Glass * If Bit 3 is 0, I2C transaction. 74508a7aa1eSSimon Glass */ 74608a7aa1eSSimon Glass reg = AUX_TX_COMM_I2C_TRANSACTION | 74708a7aa1eSSimon Glass AUX_TX_COMM_READ; 74808a7aa1eSSimon Glass writel(reg, &dp_regs->aux_ch_ctl1); 74908a7aa1eSSimon Glass 75008a7aa1eSSimon Glass /* Start AUX transaction */ 751*8c9b8dc0SSimon Glass retval = exynos_dp_start_aux_transaction(dp_regs); 75208a7aa1eSSimon Glass if (retval != EXYNOS_DP_SUCCESS) 75308a7aa1eSSimon Glass printf("%s: DP Aux Transaction fail!\n", __func__); 75408a7aa1eSSimon Glass } 75508a7aa1eSSimon Glass 75608a7aa1eSSimon Glass /* Read data */ 75708a7aa1eSSimon Glass if (retval == 0) 75808a7aa1eSSimon Glass *data = readl(&dp_regs->buf_data0); 75908a7aa1eSSimon Glass 76008a7aa1eSSimon Glass return retval; 76108a7aa1eSSimon Glass } 76208a7aa1eSSimon Glass 763*8c9b8dc0SSimon Glass int exynos_dp_read_bytes_from_i2c(struct exynos_dp *dp_regs, 764*8c9b8dc0SSimon Glass unsigned int device_addr, 765*8c9b8dc0SSimon Glass unsigned int reg_addr, unsigned int count, 766*8c9b8dc0SSimon Glass unsigned char edid[]) 76708a7aa1eSSimon Glass { 76808a7aa1eSSimon Glass unsigned int reg; 76908a7aa1eSSimon Glass unsigned int i, j; 77008a7aa1eSSimon Glass unsigned int cur_data_idx; 77108a7aa1eSSimon Glass unsigned int defer = 0; 77208a7aa1eSSimon Glass int retval = 0; 77308a7aa1eSSimon Glass 77408a7aa1eSSimon Glass for (i = 0; i < count; i += 16) { /* use 16 burst */ 77508a7aa1eSSimon Glass for (j = 0; j < 100; j++) { 77608a7aa1eSSimon Glass /* Clear AUX CH data buffer */ 77708a7aa1eSSimon Glass reg = BUF_CLR; 77808a7aa1eSSimon Glass writel(reg, &dp_regs->buffer_data_ctl); 77908a7aa1eSSimon Glass 78008a7aa1eSSimon Glass /* Set normal AUX CH command */ 78108a7aa1eSSimon Glass reg = readl(&dp_regs->aux_ch_ctl2); 78208a7aa1eSSimon Glass reg &= ~ADDR_ONLY; 78308a7aa1eSSimon Glass writel(reg, &dp_regs->aux_ch_ctl2); 78408a7aa1eSSimon Glass 78508a7aa1eSSimon Glass /* 78608a7aa1eSSimon Glass * If Rx sends defer, Tx sends only reads 78708a7aa1eSSimon Glass * request without sending addres 78808a7aa1eSSimon Glass */ 78908a7aa1eSSimon Glass if (!defer) 790*8c9b8dc0SSimon Glass retval = exynos_dp_select_i2c_device( 791*8c9b8dc0SSimon Glass dp_regs, device_addr, reg_addr + i); 79208a7aa1eSSimon Glass else 79308a7aa1eSSimon Glass defer = 0; 79408a7aa1eSSimon Glass 79508a7aa1eSSimon Glass if (retval == EXYNOS_DP_SUCCESS) { 79608a7aa1eSSimon Glass /* 79708a7aa1eSSimon Glass * Set I2C transaction and write data 79808a7aa1eSSimon Glass * If bit 3 is 1, DisplayPort transaction. 79908a7aa1eSSimon Glass * If Bit 3 is 0, I2C transaction. 80008a7aa1eSSimon Glass */ 80108a7aa1eSSimon Glass reg = AUX_LENGTH(16) | 80208a7aa1eSSimon Glass AUX_TX_COMM_I2C_TRANSACTION | 80308a7aa1eSSimon Glass AUX_TX_COMM_READ; 80408a7aa1eSSimon Glass writel(reg, &dp_regs->aux_ch_ctl1); 80508a7aa1eSSimon Glass 80608a7aa1eSSimon Glass /* Start AUX transaction */ 807*8c9b8dc0SSimon Glass retval = exynos_dp_start_aux_transaction( 808*8c9b8dc0SSimon Glass dp_regs); 80908a7aa1eSSimon Glass if (retval == 0) 81008a7aa1eSSimon Glass break; 81108a7aa1eSSimon Glass else 81208a7aa1eSSimon Glass printf("DP Aux Transaction fail!\n"); 81308a7aa1eSSimon Glass } 81408a7aa1eSSimon Glass /* Check if Rx sends defer */ 81508a7aa1eSSimon Glass reg = readl(&dp_regs->aux_rx_comm); 81608a7aa1eSSimon Glass if (reg == AUX_RX_COMM_AUX_DEFER || 81708a7aa1eSSimon Glass reg == AUX_RX_COMM_I2C_DEFER) { 81808a7aa1eSSimon Glass printf("DP Defer: %d\n", reg); 81908a7aa1eSSimon Glass defer = 1; 82008a7aa1eSSimon Glass } 82108a7aa1eSSimon Glass } 82208a7aa1eSSimon Glass 82308a7aa1eSSimon Glass for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) { 82408a7aa1eSSimon Glass reg = readl((unsigned int)&dp_regs->buf_data0 82508a7aa1eSSimon Glass + 4 * cur_data_idx); 82608a7aa1eSSimon Glass edid[i + cur_data_idx] = (unsigned char)reg; 82708a7aa1eSSimon Glass } 82808a7aa1eSSimon Glass } 82908a7aa1eSSimon Glass 83008a7aa1eSSimon Glass return retval; 83108a7aa1eSSimon Glass } 83208a7aa1eSSimon Glass 833*8c9b8dc0SSimon Glass void exynos_dp_reset_macro(struct exynos_dp *dp_regs) 83408a7aa1eSSimon Glass { 83508a7aa1eSSimon Glass unsigned int reg; 83608a7aa1eSSimon Glass 83708a7aa1eSSimon Glass reg = readl(&dp_regs->phy_test); 83808a7aa1eSSimon Glass reg |= MACRO_RST; 83908a7aa1eSSimon Glass writel(reg, &dp_regs->phy_test); 84008a7aa1eSSimon Glass 84108a7aa1eSSimon Glass /* 10 us is the minimum Macro reset time. */ 84208a7aa1eSSimon Glass mdelay(1); 84308a7aa1eSSimon Glass 84408a7aa1eSSimon Glass reg &= ~MACRO_RST; 84508a7aa1eSSimon Glass writel(reg, &dp_regs->phy_test); 84608a7aa1eSSimon Glass } 84708a7aa1eSSimon Glass 848*8c9b8dc0SSimon Glass void exynos_dp_set_link_bandwidth(struct exynos_dp *dp_regs, 849*8c9b8dc0SSimon Glass unsigned char bwtype) 85008a7aa1eSSimon Glass { 85108a7aa1eSSimon Glass unsigned int reg; 85208a7aa1eSSimon Glass 85308a7aa1eSSimon Glass reg = (unsigned int)bwtype; 85408a7aa1eSSimon Glass 85508a7aa1eSSimon Glass /* Set bandwidth to 2.7G or 1.62G */ 85608a7aa1eSSimon Glass if ((bwtype == DP_LANE_BW_1_62) || (bwtype == DP_LANE_BW_2_70)) 85708a7aa1eSSimon Glass writel(reg, &dp_regs->link_bw_set); 85808a7aa1eSSimon Glass } 85908a7aa1eSSimon Glass 860*8c9b8dc0SSimon Glass unsigned char exynos_dp_get_link_bandwidth(struct exynos_dp *dp_regs) 86108a7aa1eSSimon Glass { 86208a7aa1eSSimon Glass unsigned char ret; 86308a7aa1eSSimon Glass unsigned int reg; 86408a7aa1eSSimon Glass 86508a7aa1eSSimon Glass reg = readl(&dp_regs->link_bw_set); 86608a7aa1eSSimon Glass ret = (unsigned char)reg; 86708a7aa1eSSimon Glass 86808a7aa1eSSimon Glass return ret; 86908a7aa1eSSimon Glass } 87008a7aa1eSSimon Glass 871*8c9b8dc0SSimon Glass void exynos_dp_set_lane_count(struct exynos_dp *dp_regs, unsigned char count) 87208a7aa1eSSimon Glass { 87308a7aa1eSSimon Glass unsigned int reg; 87408a7aa1eSSimon Glass 87508a7aa1eSSimon Glass reg = (unsigned int)count; 87608a7aa1eSSimon Glass 87708a7aa1eSSimon Glass if ((count == DP_LANE_CNT_1) || (count == DP_LANE_CNT_2) || 87808a7aa1eSSimon Glass (count == DP_LANE_CNT_4)) 87908a7aa1eSSimon Glass writel(reg, &dp_regs->lane_count_set); 88008a7aa1eSSimon Glass } 88108a7aa1eSSimon Glass 882*8c9b8dc0SSimon Glass unsigned int exynos_dp_get_lane_count(struct exynos_dp *dp_regs) 88308a7aa1eSSimon Glass { 88408a7aa1eSSimon Glass unsigned int reg; 88508a7aa1eSSimon Glass 88608a7aa1eSSimon Glass reg = readl(&dp_regs->lane_count_set); 88708a7aa1eSSimon Glass 88808a7aa1eSSimon Glass return reg; 88908a7aa1eSSimon Glass } 89008a7aa1eSSimon Glass 891*8c9b8dc0SSimon Glass unsigned char exynos_dp_get_lanex_pre_emphasis(struct exynos_dp *dp_regs, 892*8c9b8dc0SSimon Glass unsigned char lanecnt) 89308a7aa1eSSimon Glass { 89408a7aa1eSSimon Glass unsigned int reg_list[DP_LANE_CNT_4] = { 89508a7aa1eSSimon Glass (unsigned int)&dp_regs->ln0_link_training_ctl, 89608a7aa1eSSimon Glass (unsigned int)&dp_regs->ln1_link_training_ctl, 89708a7aa1eSSimon Glass (unsigned int)&dp_regs->ln2_link_training_ctl, 89808a7aa1eSSimon Glass (unsigned int)&dp_regs->ln3_link_training_ctl, 89908a7aa1eSSimon Glass }; 90008a7aa1eSSimon Glass 90108a7aa1eSSimon Glass return readl(reg_list[lanecnt]); 90208a7aa1eSSimon Glass } 90308a7aa1eSSimon Glass 904*8c9b8dc0SSimon Glass void exynos_dp_set_lanex_pre_emphasis(struct exynos_dp *dp_regs, 905*8c9b8dc0SSimon Glass unsigned char request_val, 90608a7aa1eSSimon Glass unsigned char lanecnt) 90708a7aa1eSSimon Glass { 90808a7aa1eSSimon Glass unsigned int reg_list[DP_LANE_CNT_4] = { 90908a7aa1eSSimon Glass (unsigned int)&dp_regs->ln0_link_training_ctl, 91008a7aa1eSSimon Glass (unsigned int)&dp_regs->ln1_link_training_ctl, 91108a7aa1eSSimon Glass (unsigned int)&dp_regs->ln2_link_training_ctl, 91208a7aa1eSSimon Glass (unsigned int)&dp_regs->ln3_link_training_ctl, 91308a7aa1eSSimon Glass }; 91408a7aa1eSSimon Glass 91508a7aa1eSSimon Glass writel(request_val, reg_list[lanecnt]); 91608a7aa1eSSimon Glass } 91708a7aa1eSSimon Glass 918*8c9b8dc0SSimon Glass void exynos_dp_set_lane_pre_emphasis(struct exynos_dp *dp_regs, 919*8c9b8dc0SSimon Glass unsigned int level, unsigned char lanecnt) 92008a7aa1eSSimon Glass { 92108a7aa1eSSimon Glass unsigned char i; 92208a7aa1eSSimon Glass unsigned int reg; 92308a7aa1eSSimon Glass unsigned int reg_list[DP_LANE_CNT_4] = { 92408a7aa1eSSimon Glass (unsigned int)&dp_regs->ln0_link_training_ctl, 92508a7aa1eSSimon Glass (unsigned int)&dp_regs->ln1_link_training_ctl, 92608a7aa1eSSimon Glass (unsigned int)&dp_regs->ln2_link_training_ctl, 92708a7aa1eSSimon Glass (unsigned int)&dp_regs->ln3_link_training_ctl, 92808a7aa1eSSimon Glass }; 92908a7aa1eSSimon Glass unsigned int reg_shift[DP_LANE_CNT_4] = { 93008a7aa1eSSimon Glass PRE_EMPHASIS_SET_0_SHIFT, 93108a7aa1eSSimon Glass PRE_EMPHASIS_SET_1_SHIFT, 93208a7aa1eSSimon Glass PRE_EMPHASIS_SET_2_SHIFT, 93308a7aa1eSSimon Glass PRE_EMPHASIS_SET_3_SHIFT 93408a7aa1eSSimon Glass }; 93508a7aa1eSSimon Glass 93608a7aa1eSSimon Glass for (i = 0; i < lanecnt; i++) { 93708a7aa1eSSimon Glass reg = level << reg_shift[i]; 93808a7aa1eSSimon Glass writel(reg, reg_list[i]); 93908a7aa1eSSimon Glass } 94008a7aa1eSSimon Glass } 94108a7aa1eSSimon Glass 942*8c9b8dc0SSimon Glass void exynos_dp_set_training_pattern(struct exynos_dp *dp_regs, 943*8c9b8dc0SSimon Glass unsigned int pattern) 94408a7aa1eSSimon Glass { 94508a7aa1eSSimon Glass unsigned int reg = 0; 94608a7aa1eSSimon Glass 94708a7aa1eSSimon Glass switch (pattern) { 94808a7aa1eSSimon Glass case PRBS7: 94908a7aa1eSSimon Glass reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7; 95008a7aa1eSSimon Glass break; 95108a7aa1eSSimon Glass case D10_2: 95208a7aa1eSSimon Glass reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2; 95308a7aa1eSSimon Glass break; 95408a7aa1eSSimon Glass case TRAINING_PTN1: 95508a7aa1eSSimon Glass reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1; 95608a7aa1eSSimon Glass break; 95708a7aa1eSSimon Glass case TRAINING_PTN2: 95808a7aa1eSSimon Glass reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2; 95908a7aa1eSSimon Glass break; 96008a7aa1eSSimon Glass case DP_NONE: 96108a7aa1eSSimon Glass reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_DISABLE | 96208a7aa1eSSimon Glass SW_TRAINING_PATTERN_SET_NORMAL; 96308a7aa1eSSimon Glass break; 96408a7aa1eSSimon Glass default: 96508a7aa1eSSimon Glass break; 96608a7aa1eSSimon Glass } 96708a7aa1eSSimon Glass 96808a7aa1eSSimon Glass writel(reg, &dp_regs->training_ptn_set); 96908a7aa1eSSimon Glass } 97008a7aa1eSSimon Glass 971*8c9b8dc0SSimon Glass void exynos_dp_enable_enhanced_mode(struct exynos_dp *dp_regs, 972*8c9b8dc0SSimon Glass unsigned char enable) 97308a7aa1eSSimon Glass { 97408a7aa1eSSimon Glass unsigned int reg; 97508a7aa1eSSimon Glass 97608a7aa1eSSimon Glass reg = readl(&dp_regs->sys_ctl4); 97708a7aa1eSSimon Glass reg &= ~ENHANCED; 97808a7aa1eSSimon Glass 97908a7aa1eSSimon Glass if (enable) 98008a7aa1eSSimon Glass reg |= ENHANCED; 98108a7aa1eSSimon Glass 98208a7aa1eSSimon Glass writel(reg, &dp_regs->sys_ctl4); 98308a7aa1eSSimon Glass } 98408a7aa1eSSimon Glass 985*8c9b8dc0SSimon Glass void exynos_dp_enable_scrambling(struct exynos_dp *dp_regs, unsigned int enable) 98608a7aa1eSSimon Glass { 98708a7aa1eSSimon Glass unsigned int reg; 98808a7aa1eSSimon Glass 98908a7aa1eSSimon Glass reg = readl(&dp_regs->training_ptn_set); 99008a7aa1eSSimon Glass reg &= ~(SCRAMBLING_DISABLE); 99108a7aa1eSSimon Glass 99208a7aa1eSSimon Glass if (!enable) 99308a7aa1eSSimon Glass reg |= SCRAMBLING_DISABLE; 99408a7aa1eSSimon Glass 99508a7aa1eSSimon Glass writel(reg, &dp_regs->training_ptn_set); 99608a7aa1eSSimon Glass } 99708a7aa1eSSimon Glass 998*8c9b8dc0SSimon Glass int exynos_dp_init_video(struct exynos_dp *dp_regs) 99908a7aa1eSSimon Glass { 100008a7aa1eSSimon Glass unsigned int reg; 100108a7aa1eSSimon Glass 100208a7aa1eSSimon Glass /* Clear VID_CLK_CHG[1] and VID_FORMAT_CHG[3] and VSYNC_DET[7] */ 100308a7aa1eSSimon Glass reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG; 100408a7aa1eSSimon Glass writel(reg, &dp_regs->common_int_sta1); 100508a7aa1eSSimon Glass 100608a7aa1eSSimon Glass /* I_STRM__CLK detect : DE_CTL : Auto detect */ 100708a7aa1eSSimon Glass reg &= ~DET_CTRL; 100808a7aa1eSSimon Glass writel(reg, &dp_regs->sys_ctl1); 100908a7aa1eSSimon Glass 101008a7aa1eSSimon Glass return 0; 101108a7aa1eSSimon Glass } 101208a7aa1eSSimon Glass 1013*8c9b8dc0SSimon Glass void exynos_dp_config_video_slave_mode(struct exynos_dp *dp_regs, 1014*8c9b8dc0SSimon Glass struct edp_video_info *video_info) 101508a7aa1eSSimon Glass { 101608a7aa1eSSimon Glass unsigned int reg; 101708a7aa1eSSimon Glass 101808a7aa1eSSimon Glass /* Video Slave mode setting */ 101908a7aa1eSSimon Glass reg = readl(&dp_regs->func_en1); 102008a7aa1eSSimon Glass reg &= ~(MASTER_VID_FUNC_EN_N|SLAVE_VID_FUNC_EN_N); 102108a7aa1eSSimon Glass reg |= MASTER_VID_FUNC_EN_N; 102208a7aa1eSSimon Glass writel(reg, &dp_regs->func_en1); 102308a7aa1eSSimon Glass 102408a7aa1eSSimon Glass /* Configure Interlaced for slave mode video */ 102508a7aa1eSSimon Glass reg = readl(&dp_regs->video_ctl10); 102608a7aa1eSSimon Glass reg &= ~INTERACE_SCAN_CFG; 102708a7aa1eSSimon Glass reg |= (video_info->interlaced << INTERACE_SCAN_CFG_SHIFT); 102808a7aa1eSSimon Glass writel(reg, &dp_regs->video_ctl10); 102908a7aa1eSSimon Glass 103008a7aa1eSSimon Glass /* Configure V sync polarity for slave mode video */ 103108a7aa1eSSimon Glass reg = readl(&dp_regs->video_ctl10); 103208a7aa1eSSimon Glass reg &= ~VSYNC_POLARITY_CFG; 103308a7aa1eSSimon Glass reg |= (video_info->v_sync_polarity << V_S_POLARITY_CFG_SHIFT); 103408a7aa1eSSimon Glass writel(reg, &dp_regs->video_ctl10); 103508a7aa1eSSimon Glass 103608a7aa1eSSimon Glass /* Configure H sync polarity for slave mode video */ 103708a7aa1eSSimon Glass reg = readl(&dp_regs->video_ctl10); 103808a7aa1eSSimon Glass reg &= ~HSYNC_POLARITY_CFG; 103908a7aa1eSSimon Glass reg |= (video_info->h_sync_polarity << H_S_POLARITY_CFG_SHIFT); 104008a7aa1eSSimon Glass writel(reg, &dp_regs->video_ctl10); 104108a7aa1eSSimon Glass 104208a7aa1eSSimon Glass /* Set video mode to slave mode */ 104308a7aa1eSSimon Glass reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE; 104408a7aa1eSSimon Glass writel(reg, &dp_regs->soc_general_ctl); 104508a7aa1eSSimon Glass } 104608a7aa1eSSimon Glass 1047*8c9b8dc0SSimon Glass void exynos_dp_set_video_color_format(struct exynos_dp *dp_regs, 1048*8c9b8dc0SSimon Glass struct edp_video_info *video_info) 104908a7aa1eSSimon Glass { 105008a7aa1eSSimon Glass unsigned int reg; 105108a7aa1eSSimon Glass 105208a7aa1eSSimon Glass /* Configure the input color depth, color space, dynamic range */ 105308a7aa1eSSimon Glass reg = (video_info->dynamic_range << IN_D_RANGE_SHIFT) | 105408a7aa1eSSimon Glass (video_info->color_depth << IN_BPC_SHIFT) | 105508a7aa1eSSimon Glass (video_info->color_space << IN_COLOR_F_SHIFT); 105608a7aa1eSSimon Glass writel(reg, &dp_regs->video_ctl2); 105708a7aa1eSSimon Glass 105808a7aa1eSSimon Glass /* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */ 105908a7aa1eSSimon Glass reg = readl(&dp_regs->video_ctl3); 106008a7aa1eSSimon Glass reg &= ~IN_YC_COEFFI_MASK; 106108a7aa1eSSimon Glass if (video_info->ycbcr_coeff) 106208a7aa1eSSimon Glass reg |= IN_YC_COEFFI_ITU709; 106308a7aa1eSSimon Glass else 106408a7aa1eSSimon Glass reg |= IN_YC_COEFFI_ITU601; 106508a7aa1eSSimon Glass writel(reg, &dp_regs->video_ctl3); 106608a7aa1eSSimon Glass } 106708a7aa1eSSimon Glass 1068*8c9b8dc0SSimon Glass int exynos_dp_config_video_bist(struct exynos_dp *dp_regs, 1069*8c9b8dc0SSimon Glass struct edp_device_info *edp_info) 107008a7aa1eSSimon Glass { 107108a7aa1eSSimon Glass unsigned int reg; 107208a7aa1eSSimon Glass unsigned int bist_type = 0; 107308a7aa1eSSimon Glass struct edp_video_info video_info = edp_info->video_info; 107408a7aa1eSSimon Glass 107508a7aa1eSSimon Glass /* For master mode, you don't need to set the video format */ 107608a7aa1eSSimon Glass if (video_info.master_mode == 0) { 107708a7aa1eSSimon Glass writel(TOTAL_LINE_CFG_L(edp_info->disp_info.v_total), 107808a7aa1eSSimon Glass &dp_regs->total_ln_cfg_l); 107908a7aa1eSSimon Glass writel(TOTAL_LINE_CFG_H(edp_info->disp_info.v_total), 108008a7aa1eSSimon Glass &dp_regs->total_ln_cfg_h); 108108a7aa1eSSimon Glass writel(ACTIVE_LINE_CFG_L(edp_info->disp_info.v_res), 108208a7aa1eSSimon Glass &dp_regs->active_ln_cfg_l); 108308a7aa1eSSimon Glass writel(ACTIVE_LINE_CFG_H(edp_info->disp_info.v_res), 108408a7aa1eSSimon Glass &dp_regs->active_ln_cfg_h); 108508a7aa1eSSimon Glass writel(edp_info->disp_info.v_sync_width, 108608a7aa1eSSimon Glass &dp_regs->vsw_cfg); 108708a7aa1eSSimon Glass writel(edp_info->disp_info.v_back_porch, 108808a7aa1eSSimon Glass &dp_regs->vbp_cfg); 108908a7aa1eSSimon Glass writel(edp_info->disp_info.v_front_porch, 109008a7aa1eSSimon Glass &dp_regs->vfp_cfg); 109108a7aa1eSSimon Glass 109208a7aa1eSSimon Glass writel(TOTAL_PIXEL_CFG_L(edp_info->disp_info.h_total), 109308a7aa1eSSimon Glass &dp_regs->total_pix_cfg_l); 109408a7aa1eSSimon Glass writel(TOTAL_PIXEL_CFG_H(edp_info->disp_info.h_total), 109508a7aa1eSSimon Glass &dp_regs->total_pix_cfg_h); 109608a7aa1eSSimon Glass writel(ACTIVE_PIXEL_CFG_L(edp_info->disp_info.h_res), 109708a7aa1eSSimon Glass &dp_regs->active_pix_cfg_l); 109808a7aa1eSSimon Glass writel(ACTIVE_PIXEL_CFG_H(edp_info->disp_info.h_res), 109908a7aa1eSSimon Glass &dp_regs->active_pix_cfg_h); 110008a7aa1eSSimon Glass writel(H_F_PORCH_CFG_L(edp_info->disp_info.h_front_porch), 110108a7aa1eSSimon Glass &dp_regs->hfp_cfg_l); 110208a7aa1eSSimon Glass writel(H_F_PORCH_CFG_H(edp_info->disp_info.h_front_porch), 110308a7aa1eSSimon Glass &dp_regs->hfp_cfg_h); 110408a7aa1eSSimon Glass writel(H_SYNC_PORCH_CFG_L(edp_info->disp_info.h_sync_width), 110508a7aa1eSSimon Glass &dp_regs->hsw_cfg_l); 110608a7aa1eSSimon Glass writel(H_SYNC_PORCH_CFG_H(edp_info->disp_info.h_sync_width), 110708a7aa1eSSimon Glass &dp_regs->hsw_cfg_h); 110808a7aa1eSSimon Glass writel(H_B_PORCH_CFG_L(edp_info->disp_info.h_back_porch), 110908a7aa1eSSimon Glass &dp_regs->hbp_cfg_l); 111008a7aa1eSSimon Glass writel(H_B_PORCH_CFG_H(edp_info->disp_info.h_back_porch), 111108a7aa1eSSimon Glass &dp_regs->hbp_cfg_h); 111208a7aa1eSSimon Glass 111308a7aa1eSSimon Glass /* 111408a7aa1eSSimon Glass * Set SLAVE_I_SCAN_CFG[2], VSYNC_P_CFG[1], 111508a7aa1eSSimon Glass * HSYNC_P_CFG[0] properly 111608a7aa1eSSimon Glass */ 111708a7aa1eSSimon Glass reg = (video_info.interlaced << INTERACE_SCAN_CFG_SHIFT | 111808a7aa1eSSimon Glass video_info.v_sync_polarity << V_S_POLARITY_CFG_SHIFT | 111908a7aa1eSSimon Glass video_info.h_sync_polarity << H_S_POLARITY_CFG_SHIFT); 112008a7aa1eSSimon Glass writel(reg, &dp_regs->video_ctl10); 112108a7aa1eSSimon Glass } 112208a7aa1eSSimon Glass 112308a7aa1eSSimon Glass /* BIST color bar width set--set to each bar is 32 pixel width */ 112408a7aa1eSSimon Glass switch (video_info.bist_pattern) { 112508a7aa1eSSimon Glass case COLORBAR_32: 112608a7aa1eSSimon Glass bist_type = BIST_WIDTH_BAR_32_PIXEL | 112708a7aa1eSSimon Glass BIST_TYPE_COLOR_BAR; 112808a7aa1eSSimon Glass break; 112908a7aa1eSSimon Glass case COLORBAR_64: 113008a7aa1eSSimon Glass bist_type = BIST_WIDTH_BAR_64_PIXEL | 113108a7aa1eSSimon Glass BIST_TYPE_COLOR_BAR; 113208a7aa1eSSimon Glass break; 113308a7aa1eSSimon Glass case WHITE_GRAY_BALCKBAR_32: 113408a7aa1eSSimon Glass bist_type = BIST_WIDTH_BAR_32_PIXEL | 113508a7aa1eSSimon Glass BIST_TYPE_WHITE_GRAY_BLACK_BAR; 113608a7aa1eSSimon Glass break; 113708a7aa1eSSimon Glass case WHITE_GRAY_BALCKBAR_64: 113808a7aa1eSSimon Glass bist_type = BIST_WIDTH_BAR_64_PIXEL | 113908a7aa1eSSimon Glass BIST_TYPE_WHITE_GRAY_BLACK_BAR; 114008a7aa1eSSimon Glass break; 114108a7aa1eSSimon Glass case MOBILE_WHITEBAR_32: 114208a7aa1eSSimon Glass bist_type = BIST_WIDTH_BAR_32_PIXEL | 114308a7aa1eSSimon Glass BIST_TYPE_MOBILE_WHITE_BAR; 114408a7aa1eSSimon Glass break; 114508a7aa1eSSimon Glass case MOBILE_WHITEBAR_64: 114608a7aa1eSSimon Glass bist_type = BIST_WIDTH_BAR_64_PIXEL | 114708a7aa1eSSimon Glass BIST_TYPE_MOBILE_WHITE_BAR; 114808a7aa1eSSimon Glass break; 114908a7aa1eSSimon Glass default: 115008a7aa1eSSimon Glass return -1; 115108a7aa1eSSimon Glass } 115208a7aa1eSSimon Glass 115308a7aa1eSSimon Glass reg = bist_type; 115408a7aa1eSSimon Glass writel(reg, &dp_regs->video_ctl4); 115508a7aa1eSSimon Glass 115608a7aa1eSSimon Glass return 0; 115708a7aa1eSSimon Glass } 115808a7aa1eSSimon Glass 1159*8c9b8dc0SSimon Glass unsigned int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp *dp_regs) 116008a7aa1eSSimon Glass { 116108a7aa1eSSimon Glass unsigned int reg; 116208a7aa1eSSimon Glass 116308a7aa1eSSimon Glass /* Update Video stream clk detect status */ 116408a7aa1eSSimon Glass reg = readl(&dp_regs->sys_ctl1); 116508a7aa1eSSimon Glass writel(reg, &dp_regs->sys_ctl1); 116608a7aa1eSSimon Glass 116708a7aa1eSSimon Glass reg = readl(&dp_regs->sys_ctl1); 116808a7aa1eSSimon Glass 116908a7aa1eSSimon Glass if (!(reg & DET_STA)) { 117008a7aa1eSSimon Glass debug("DP Input stream clock not detected.\n"); 117108a7aa1eSSimon Glass return -EIO; 117208a7aa1eSSimon Glass } 117308a7aa1eSSimon Glass 117408a7aa1eSSimon Glass return EXYNOS_DP_SUCCESS; 117508a7aa1eSSimon Glass } 117608a7aa1eSSimon Glass 1177*8c9b8dc0SSimon Glass void exynos_dp_set_video_cr_mn(struct exynos_dp *dp_regs, unsigned int type, 1178*8c9b8dc0SSimon Glass unsigned int m_value, unsigned int n_value) 117908a7aa1eSSimon Glass { 118008a7aa1eSSimon Glass unsigned int reg; 118108a7aa1eSSimon Glass 118208a7aa1eSSimon Glass if (type == REGISTER_M) { 118308a7aa1eSSimon Glass reg = readl(&dp_regs->sys_ctl4); 118408a7aa1eSSimon Glass reg |= FIX_M_VID; 118508a7aa1eSSimon Glass writel(reg, &dp_regs->sys_ctl4); 118608a7aa1eSSimon Glass reg = M_VID0_CFG(m_value); 118708a7aa1eSSimon Glass writel(reg, &dp_regs->m_vid0); 118808a7aa1eSSimon Glass reg = M_VID1_CFG(m_value); 118908a7aa1eSSimon Glass writel(reg, &dp_regs->m_vid1); 119008a7aa1eSSimon Glass reg = M_VID2_CFG(m_value); 119108a7aa1eSSimon Glass writel(reg, &dp_regs->m_vid2); 119208a7aa1eSSimon Glass 119308a7aa1eSSimon Glass reg = N_VID0_CFG(n_value); 119408a7aa1eSSimon Glass writel(reg, &dp_regs->n_vid0); 119508a7aa1eSSimon Glass reg = N_VID1_CFG(n_value); 119608a7aa1eSSimon Glass writel(reg, &dp_regs->n_vid1); 119708a7aa1eSSimon Glass reg = N_VID2_CFG(n_value); 119808a7aa1eSSimon Glass writel(reg, &dp_regs->n_vid2); 119908a7aa1eSSimon Glass } else { 120008a7aa1eSSimon Glass reg = readl(&dp_regs->sys_ctl4); 120108a7aa1eSSimon Glass reg &= ~FIX_M_VID; 120208a7aa1eSSimon Glass writel(reg, &dp_regs->sys_ctl4); 120308a7aa1eSSimon Glass } 120408a7aa1eSSimon Glass } 120508a7aa1eSSimon Glass 1206*8c9b8dc0SSimon Glass void exynos_dp_set_video_timing_mode(struct exynos_dp *dp_regs, 1207*8c9b8dc0SSimon Glass unsigned int type) 120808a7aa1eSSimon Glass { 120908a7aa1eSSimon Glass unsigned int reg; 121008a7aa1eSSimon Glass 121108a7aa1eSSimon Glass reg = readl(&dp_regs->video_ctl10); 121208a7aa1eSSimon Glass reg &= ~FORMAT_SEL; 121308a7aa1eSSimon Glass 121408a7aa1eSSimon Glass if (type != VIDEO_TIMING_FROM_CAPTURE) 121508a7aa1eSSimon Glass reg |= FORMAT_SEL; 121608a7aa1eSSimon Glass 121708a7aa1eSSimon Glass writel(reg, &dp_regs->video_ctl10); 121808a7aa1eSSimon Glass } 121908a7aa1eSSimon Glass 1220*8c9b8dc0SSimon Glass void exynos_dp_enable_video_master(struct exynos_dp *dp_regs, 1221*8c9b8dc0SSimon Glass unsigned int enable) 122208a7aa1eSSimon Glass { 122308a7aa1eSSimon Glass unsigned int reg; 122408a7aa1eSSimon Glass 122508a7aa1eSSimon Glass reg = readl(&dp_regs->soc_general_ctl); 122608a7aa1eSSimon Glass if (enable) { 122708a7aa1eSSimon Glass reg &= ~VIDEO_MODE_MASK; 122808a7aa1eSSimon Glass reg |= VIDEO_MASTER_MODE_EN | VIDEO_MODE_MASTER_MODE; 122908a7aa1eSSimon Glass } else { 123008a7aa1eSSimon Glass reg &= ~VIDEO_MODE_MASK; 123108a7aa1eSSimon Glass reg |= VIDEO_MODE_SLAVE_MODE; 123208a7aa1eSSimon Glass } 123308a7aa1eSSimon Glass 123408a7aa1eSSimon Glass writel(reg, &dp_regs->soc_general_ctl); 123508a7aa1eSSimon Glass } 123608a7aa1eSSimon Glass 1237*8c9b8dc0SSimon Glass void exynos_dp_start_video(struct exynos_dp *dp_regs) 123808a7aa1eSSimon Glass { 123908a7aa1eSSimon Glass unsigned int reg; 124008a7aa1eSSimon Glass 124108a7aa1eSSimon Glass /* Enable Video input and disable Mute */ 124208a7aa1eSSimon Glass reg = readl(&dp_regs->video_ctl1); 124308a7aa1eSSimon Glass reg |= VIDEO_EN; 124408a7aa1eSSimon Glass writel(reg, &dp_regs->video_ctl1); 124508a7aa1eSSimon Glass } 124608a7aa1eSSimon Glass 1247*8c9b8dc0SSimon Glass unsigned int exynos_dp_is_video_stream_on(struct exynos_dp *dp_regs) 124808a7aa1eSSimon Glass { 124908a7aa1eSSimon Glass unsigned int reg; 125008a7aa1eSSimon Glass 125108a7aa1eSSimon Glass /* Update STRM_VALID */ 125208a7aa1eSSimon Glass reg = readl(&dp_regs->sys_ctl3); 125308a7aa1eSSimon Glass writel(reg, &dp_regs->sys_ctl3); 125408a7aa1eSSimon Glass 125508a7aa1eSSimon Glass reg = readl(&dp_regs->sys_ctl3); 125608a7aa1eSSimon Glass if (!(reg & STRM_VALID)) 125708a7aa1eSSimon Glass return -EIO; 125808a7aa1eSSimon Glass 125908a7aa1eSSimon Glass return EXYNOS_DP_SUCCESS; 126008a7aa1eSSimon Glass } 1261