13424e3a4SYakir Yang /* 23424e3a4SYakir Yang * Analogix DP (Display port) core register interface driver. 33424e3a4SYakir Yang * 43424e3a4SYakir Yang * Copyright (C) 2012 Samsung Electronics Co., Ltd. 53424e3a4SYakir Yang * Author: Jingoo Han <jg1.han@samsung.com> 63424e3a4SYakir Yang * 73424e3a4SYakir Yang * This program is free software; you can redistribute it and/or modify it 83424e3a4SYakir Yang * under the terms of the GNU General Public License as published by the 93424e3a4SYakir Yang * Free Software Foundation; either version 2 of the License, or (at your 103424e3a4SYakir Yang * option) any later version. 113424e3a4SYakir Yang */ 123424e3a4SYakir Yang 133424e3a4SYakir Yang #include <linux/device.h> 143424e3a4SYakir Yang #include <linux/io.h> 153424e3a4SYakir Yang #include <linux/delay.h> 163424e3a4SYakir Yang #include <linux/gpio.h> 173424e3a4SYakir Yang 183424e3a4SYakir Yang #include "analogix_dp_core.h" 193424e3a4SYakir Yang #include "analogix_dp_reg.h" 203424e3a4SYakir Yang 213424e3a4SYakir Yang #define COMMON_INT_MASK_1 0 223424e3a4SYakir Yang #define COMMON_INT_MASK_2 0 233424e3a4SYakir Yang #define COMMON_INT_MASK_3 0 243424e3a4SYakir Yang #define COMMON_INT_MASK_4 (HOTPLUG_CHG | HPD_LOST | PLUG) 253424e3a4SYakir Yang #define INT_STA_MASK INT_HPD 263424e3a4SYakir Yang 273424e3a4SYakir Yang void analogix_dp_enable_video_mute(struct analogix_dp_device *dp, bool enable) 283424e3a4SYakir Yang { 293424e3a4SYakir Yang u32 reg; 303424e3a4SYakir Yang 313424e3a4SYakir Yang if (enable) { 32092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); 333424e3a4SYakir Yang reg |= HDCP_VIDEO_MUTE; 34092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); 353424e3a4SYakir Yang } else { 36092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); 373424e3a4SYakir Yang reg &= ~HDCP_VIDEO_MUTE; 38092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); 393424e3a4SYakir Yang } 403424e3a4SYakir Yang } 413424e3a4SYakir Yang 423424e3a4SYakir Yang void analogix_dp_stop_video(struct analogix_dp_device *dp) 433424e3a4SYakir Yang { 443424e3a4SYakir Yang u32 reg; 453424e3a4SYakir Yang 46092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); 473424e3a4SYakir Yang reg &= ~VIDEO_EN; 48092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); 493424e3a4SYakir Yang } 503424e3a4SYakir Yang 513424e3a4SYakir Yang void analogix_dp_lane_swap(struct analogix_dp_device *dp, bool enable) 523424e3a4SYakir Yang { 533424e3a4SYakir Yang u32 reg; 543424e3a4SYakir Yang 553424e3a4SYakir Yang if (enable) 563424e3a4SYakir Yang reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 | 573424e3a4SYakir Yang LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3; 583424e3a4SYakir Yang else 593424e3a4SYakir Yang reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 | 603424e3a4SYakir Yang LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0; 613424e3a4SYakir Yang 62092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_LANE_MAP); 633424e3a4SYakir Yang } 643424e3a4SYakir Yang 653424e3a4SYakir Yang void analogix_dp_init_analog_param(struct analogix_dp_device *dp) 663424e3a4SYakir Yang { 673424e3a4SYakir Yang u32 reg; 683424e3a4SYakir Yang 693424e3a4SYakir Yang reg = TX_TERMINAL_CTRL_50_OHM; 70092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_ANALOG_CTL_1); 713424e3a4SYakir Yang 723424e3a4SYakir Yang reg = SEL_24M | TX_DVDD_BIT_1_0625V; 73092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_ANALOG_CTL_2); 743424e3a4SYakir Yang 753424e3a4SYakir Yang reg = DRIVE_DVDD_BIT_1_0625V | VCO_BIT_600_MICRO; 76092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_ANALOG_CTL_3); 773424e3a4SYakir Yang 783424e3a4SYakir Yang reg = PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM | 793424e3a4SYakir Yang TX_CUR1_2X | TX_CUR_16_MA; 80092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_PLL_FILTER_CTL_1); 813424e3a4SYakir Yang 823424e3a4SYakir Yang reg = CH3_AMP_400_MV | CH2_AMP_400_MV | 833424e3a4SYakir Yang CH1_AMP_400_MV | CH0_AMP_400_MV; 84092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_TX_AMP_TUNING_CTL); 853424e3a4SYakir Yang } 863424e3a4SYakir Yang 873424e3a4SYakir Yang void analogix_dp_init_interrupt(struct analogix_dp_device *dp) 883424e3a4SYakir Yang { 893424e3a4SYakir Yang /* Set interrupt pin assertion polarity as high */ 90092f8994SHeiko Stuebner writel(INT_POL1 | INT_POL0, dp->reg_base + ANALOGIX_DP_INT_CTL); 913424e3a4SYakir Yang 923424e3a4SYakir Yang /* Clear pending regisers */ 93092f8994SHeiko Stuebner writel(0xff, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_1); 94092f8994SHeiko Stuebner writel(0x4f, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_2); 95092f8994SHeiko Stuebner writel(0xe0, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_3); 96092f8994SHeiko Stuebner writel(0xe7, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_4); 97092f8994SHeiko Stuebner writel(0x63, dp->reg_base + ANALOGIX_DP_INT_STA); 983424e3a4SYakir Yang 993424e3a4SYakir Yang /* 0:mask,1: unmask */ 100092f8994SHeiko Stuebner writel(0x00, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_1); 101092f8994SHeiko Stuebner writel(0x00, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_2); 102092f8994SHeiko Stuebner writel(0x00, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_3); 103092f8994SHeiko Stuebner writel(0x00, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4); 104092f8994SHeiko Stuebner writel(0x00, dp->reg_base + ANALOGIX_DP_INT_STA_MASK); 1053424e3a4SYakir Yang } 1063424e3a4SYakir Yang 1073424e3a4SYakir Yang void analogix_dp_reset(struct analogix_dp_device *dp) 1083424e3a4SYakir Yang { 1093424e3a4SYakir Yang u32 reg; 1103424e3a4SYakir Yang 1113424e3a4SYakir Yang analogix_dp_stop_video(dp); 1123424e3a4SYakir Yang analogix_dp_enable_video_mute(dp, 0); 1133424e3a4SYakir Yang 1143424e3a4SYakir Yang reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N | 1153424e3a4SYakir Yang AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N | 1163424e3a4SYakir Yang HDCP_FUNC_EN_N | SW_FUNC_EN_N; 117092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_1); 1183424e3a4SYakir Yang 1193424e3a4SYakir Yang reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N | 1203424e3a4SYakir Yang SERDES_FIFO_FUNC_EN_N | 1213424e3a4SYakir Yang LS_CLK_DOMAIN_FUNC_EN_N; 122092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_2); 1233424e3a4SYakir Yang 1243424e3a4SYakir Yang usleep_range(20, 30); 1253424e3a4SYakir Yang 1263424e3a4SYakir Yang analogix_dp_lane_swap(dp, 0); 1273424e3a4SYakir Yang 128092f8994SHeiko Stuebner writel(0x0, dp->reg_base + ANALOGIX_DP_SYS_CTL_1); 129092f8994SHeiko Stuebner writel(0x40, dp->reg_base + ANALOGIX_DP_SYS_CTL_2); 130092f8994SHeiko Stuebner writel(0x0, dp->reg_base + ANALOGIX_DP_SYS_CTL_3); 131092f8994SHeiko Stuebner writel(0x0, dp->reg_base + ANALOGIX_DP_SYS_CTL_4); 1323424e3a4SYakir Yang 133092f8994SHeiko Stuebner writel(0x0, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); 134092f8994SHeiko Stuebner writel(0x0, dp->reg_base + ANALOGIX_DP_HDCP_CTL); 1353424e3a4SYakir Yang 136092f8994SHeiko Stuebner writel(0x5e, dp->reg_base + ANALOGIX_DP_HPD_DEGLITCH_L); 137092f8994SHeiko Stuebner writel(0x1a, dp->reg_base + ANALOGIX_DP_HPD_DEGLITCH_H); 1383424e3a4SYakir Yang 139092f8994SHeiko Stuebner writel(0x10, dp->reg_base + ANALOGIX_DP_LINK_DEBUG_CTL); 1403424e3a4SYakir Yang 141092f8994SHeiko Stuebner writel(0x0, dp->reg_base + ANALOGIX_DP_PHY_TEST); 1423424e3a4SYakir Yang 143092f8994SHeiko Stuebner writel(0x0, dp->reg_base + ANALOGIX_DP_VIDEO_FIFO_THRD); 144092f8994SHeiko Stuebner writel(0x20, dp->reg_base + ANALOGIX_DP_AUDIO_MARGIN); 1453424e3a4SYakir Yang 146092f8994SHeiko Stuebner writel(0x4, dp->reg_base + ANALOGIX_DP_M_VID_GEN_FILTER_TH); 147092f8994SHeiko Stuebner writel(0x2, dp->reg_base + ANALOGIX_DP_M_AUD_GEN_FILTER_TH); 1483424e3a4SYakir Yang 149092f8994SHeiko Stuebner writel(0x00000101, dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL); 1503424e3a4SYakir Yang } 1513424e3a4SYakir Yang 1523424e3a4SYakir Yang void analogix_dp_swreset(struct analogix_dp_device *dp) 1533424e3a4SYakir Yang { 154092f8994SHeiko Stuebner writel(RESET_DP_TX, dp->reg_base + ANALOGIX_DP_TX_SW_RESET); 1553424e3a4SYakir Yang } 1563424e3a4SYakir Yang 1573424e3a4SYakir Yang void analogix_dp_config_interrupt(struct analogix_dp_device *dp) 1583424e3a4SYakir Yang { 1593424e3a4SYakir Yang u32 reg; 1603424e3a4SYakir Yang 1613424e3a4SYakir Yang /* 0: mask, 1: unmask */ 1623424e3a4SYakir Yang reg = COMMON_INT_MASK_1; 163092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_1); 1643424e3a4SYakir Yang 1653424e3a4SYakir Yang reg = COMMON_INT_MASK_2; 166092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_2); 1673424e3a4SYakir Yang 1683424e3a4SYakir Yang reg = COMMON_INT_MASK_3; 169092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_3); 1703424e3a4SYakir Yang 1713424e3a4SYakir Yang reg = COMMON_INT_MASK_4; 172092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4); 1733424e3a4SYakir Yang 1743424e3a4SYakir Yang reg = INT_STA_MASK; 175092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA_MASK); 1763424e3a4SYakir Yang } 1773424e3a4SYakir Yang 1783424e3a4SYakir Yang enum pll_status analogix_dp_get_pll_lock_status(struct analogix_dp_device *dp) 1793424e3a4SYakir Yang { 1803424e3a4SYakir Yang u32 reg; 1813424e3a4SYakir Yang 182092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_DEBUG_CTL); 1833424e3a4SYakir Yang if (reg & PLL_LOCK) 1843424e3a4SYakir Yang return PLL_LOCKED; 1853424e3a4SYakir Yang else 1863424e3a4SYakir Yang return PLL_UNLOCKED; 1873424e3a4SYakir Yang } 1883424e3a4SYakir Yang 1893424e3a4SYakir Yang void analogix_dp_set_pll_power_down(struct analogix_dp_device *dp, bool enable) 1903424e3a4SYakir Yang { 1913424e3a4SYakir Yang u32 reg; 1923424e3a4SYakir Yang 1933424e3a4SYakir Yang if (enable) { 194092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_PLL_CTL); 1953424e3a4SYakir Yang reg |= DP_PLL_PD; 196092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_PLL_CTL); 1973424e3a4SYakir Yang } else { 198092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_PLL_CTL); 1993424e3a4SYakir Yang reg &= ~DP_PLL_PD; 200092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_PLL_CTL); 2013424e3a4SYakir Yang } 2023424e3a4SYakir Yang } 2033424e3a4SYakir Yang 2043424e3a4SYakir Yang void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp, 2053424e3a4SYakir Yang enum analog_power_block block, 2063424e3a4SYakir Yang bool enable) 2073424e3a4SYakir Yang { 2083424e3a4SYakir Yang u32 reg; 2093424e3a4SYakir Yang 2103424e3a4SYakir Yang switch (block) { 2113424e3a4SYakir Yang case AUX_BLOCK: 2123424e3a4SYakir Yang if (enable) { 213092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD); 2143424e3a4SYakir Yang reg |= AUX_PD; 215092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD); 2163424e3a4SYakir Yang } else { 217092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD); 2183424e3a4SYakir Yang reg &= ~AUX_PD; 219092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD); 2203424e3a4SYakir Yang } 2213424e3a4SYakir Yang break; 2223424e3a4SYakir Yang case CH0_BLOCK: 2233424e3a4SYakir Yang if (enable) { 224092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD); 2253424e3a4SYakir Yang reg |= CH0_PD; 226092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD); 2273424e3a4SYakir Yang } else { 228092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD); 2293424e3a4SYakir Yang reg &= ~CH0_PD; 230092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD); 2313424e3a4SYakir Yang } 2323424e3a4SYakir Yang break; 2333424e3a4SYakir Yang case CH1_BLOCK: 2343424e3a4SYakir Yang if (enable) { 235092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD); 2363424e3a4SYakir Yang reg |= CH1_PD; 237092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD); 2383424e3a4SYakir Yang } else { 239092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD); 2403424e3a4SYakir Yang reg &= ~CH1_PD; 241092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD); 2423424e3a4SYakir Yang } 2433424e3a4SYakir Yang break; 2443424e3a4SYakir Yang case CH2_BLOCK: 2453424e3a4SYakir Yang if (enable) { 246092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD); 2473424e3a4SYakir Yang reg |= CH2_PD; 248092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD); 2493424e3a4SYakir Yang } else { 250092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD); 2513424e3a4SYakir Yang reg &= ~CH2_PD; 252092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD); 2533424e3a4SYakir Yang } 2543424e3a4SYakir Yang break; 2553424e3a4SYakir Yang case CH3_BLOCK: 2563424e3a4SYakir Yang if (enable) { 257092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD); 2583424e3a4SYakir Yang reg |= CH3_PD; 259092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD); 2603424e3a4SYakir Yang } else { 261092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD); 2623424e3a4SYakir Yang reg &= ~CH3_PD; 263092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD); 2643424e3a4SYakir Yang } 2653424e3a4SYakir Yang break; 2663424e3a4SYakir Yang case ANALOG_TOTAL: 2673424e3a4SYakir Yang if (enable) { 268092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD); 2693424e3a4SYakir Yang reg |= DP_PHY_PD; 270092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD); 2713424e3a4SYakir Yang } else { 272092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_PHY_PD); 2733424e3a4SYakir Yang reg &= ~DP_PHY_PD; 274092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD); 2753424e3a4SYakir Yang } 2763424e3a4SYakir Yang break; 2773424e3a4SYakir Yang case POWER_ALL: 2783424e3a4SYakir Yang if (enable) { 2793424e3a4SYakir Yang reg = DP_PHY_PD | AUX_PD | CH3_PD | CH2_PD | 2803424e3a4SYakir Yang CH1_PD | CH0_PD; 281092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_PHY_PD); 2823424e3a4SYakir Yang } else { 283092f8994SHeiko Stuebner writel(0x00, dp->reg_base + ANALOGIX_DP_PHY_PD); 2843424e3a4SYakir Yang } 2853424e3a4SYakir Yang break; 2863424e3a4SYakir Yang default: 2873424e3a4SYakir Yang break; 2883424e3a4SYakir Yang } 2893424e3a4SYakir Yang } 2903424e3a4SYakir Yang 2913424e3a4SYakir Yang void analogix_dp_init_analog_func(struct analogix_dp_device *dp) 2923424e3a4SYakir Yang { 2933424e3a4SYakir Yang u32 reg; 2943424e3a4SYakir Yang int timeout_loop = 0; 2953424e3a4SYakir Yang 2963424e3a4SYakir Yang analogix_dp_set_analog_power_down(dp, POWER_ALL, 0); 2973424e3a4SYakir Yang 2983424e3a4SYakir Yang reg = PLL_LOCK_CHG; 299092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_1); 3003424e3a4SYakir Yang 301092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_DEBUG_CTL); 3023424e3a4SYakir Yang reg &= ~(F_PLL_LOCK | PLL_LOCK_CTRL); 303092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_DEBUG_CTL); 3043424e3a4SYakir Yang 3053424e3a4SYakir Yang /* Power up PLL */ 3063424e3a4SYakir Yang if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { 3073424e3a4SYakir Yang analogix_dp_set_pll_power_down(dp, 0); 3083424e3a4SYakir Yang 3093424e3a4SYakir Yang while (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { 3103424e3a4SYakir Yang timeout_loop++; 3113424e3a4SYakir Yang if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { 3123424e3a4SYakir Yang dev_err(dp->dev, "failed to get pll lock status\n"); 3133424e3a4SYakir Yang return; 3143424e3a4SYakir Yang } 3153424e3a4SYakir Yang usleep_range(10, 20); 3163424e3a4SYakir Yang } 3173424e3a4SYakir Yang } 3183424e3a4SYakir Yang 3193424e3a4SYakir Yang /* Enable Serdes FIFO function and Link symbol clock domain module */ 320092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_2); 3213424e3a4SYakir Yang reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N 3223424e3a4SYakir Yang | AUX_FUNC_EN_N); 323092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_2); 3243424e3a4SYakir Yang } 3253424e3a4SYakir Yang 3263424e3a4SYakir Yang void analogix_dp_clear_hotplug_interrupts(struct analogix_dp_device *dp) 3273424e3a4SYakir Yang { 3283424e3a4SYakir Yang u32 reg; 3293424e3a4SYakir Yang 3303424e3a4SYakir Yang if (gpio_is_valid(dp->hpd_gpio)) 3313424e3a4SYakir Yang return; 3323424e3a4SYakir Yang 3333424e3a4SYakir Yang reg = HOTPLUG_CHG | HPD_LOST | PLUG; 334092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_4); 3353424e3a4SYakir Yang 3363424e3a4SYakir Yang reg = INT_HPD; 337092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA); 3383424e3a4SYakir Yang } 3393424e3a4SYakir Yang 3403424e3a4SYakir Yang void analogix_dp_init_hpd(struct analogix_dp_device *dp) 3413424e3a4SYakir Yang { 3423424e3a4SYakir Yang u32 reg; 3433424e3a4SYakir Yang 3443424e3a4SYakir Yang if (gpio_is_valid(dp->hpd_gpio)) 3453424e3a4SYakir Yang return; 3463424e3a4SYakir Yang 3473424e3a4SYakir Yang analogix_dp_clear_hotplug_interrupts(dp); 3483424e3a4SYakir Yang 349092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_3); 3503424e3a4SYakir Yang reg &= ~(F_HPD | HPD_CTRL); 351092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_3); 3523424e3a4SYakir Yang } 3533424e3a4SYakir Yang 3543424e3a4SYakir Yang enum dp_irq_type analogix_dp_get_irq_type(struct analogix_dp_device *dp) 3553424e3a4SYakir Yang { 3563424e3a4SYakir Yang u32 reg; 3573424e3a4SYakir Yang 3583424e3a4SYakir Yang if (gpio_is_valid(dp->hpd_gpio)) { 3593424e3a4SYakir Yang reg = gpio_get_value(dp->hpd_gpio); 3603424e3a4SYakir Yang if (reg) 3613424e3a4SYakir Yang return DP_IRQ_TYPE_HP_CABLE_IN; 3623424e3a4SYakir Yang else 3633424e3a4SYakir Yang return DP_IRQ_TYPE_HP_CABLE_OUT; 3643424e3a4SYakir Yang } else { 3653424e3a4SYakir Yang /* Parse hotplug interrupt status register */ 366092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_4); 3673424e3a4SYakir Yang 3683424e3a4SYakir Yang if (reg & PLUG) 3693424e3a4SYakir Yang return DP_IRQ_TYPE_HP_CABLE_IN; 3703424e3a4SYakir Yang 3713424e3a4SYakir Yang if (reg & HPD_LOST) 3723424e3a4SYakir Yang return DP_IRQ_TYPE_HP_CABLE_OUT; 3733424e3a4SYakir Yang 3743424e3a4SYakir Yang if (reg & HOTPLUG_CHG) 3753424e3a4SYakir Yang return DP_IRQ_TYPE_HP_CHANGE; 3763424e3a4SYakir Yang 3773424e3a4SYakir Yang return DP_IRQ_TYPE_UNKNOWN; 3783424e3a4SYakir Yang } 3793424e3a4SYakir Yang } 3803424e3a4SYakir Yang 3813424e3a4SYakir Yang void analogix_dp_reset_aux(struct analogix_dp_device *dp) 3823424e3a4SYakir Yang { 3833424e3a4SYakir Yang u32 reg; 3843424e3a4SYakir Yang 3853424e3a4SYakir Yang /* Disable AUX channel module */ 386092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_2); 3873424e3a4SYakir Yang reg |= AUX_FUNC_EN_N; 388092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_2); 3893424e3a4SYakir Yang } 3903424e3a4SYakir Yang 3913424e3a4SYakir Yang void analogix_dp_init_aux(struct analogix_dp_device *dp) 3923424e3a4SYakir Yang { 3933424e3a4SYakir Yang u32 reg; 3943424e3a4SYakir Yang 3953424e3a4SYakir Yang /* Clear inerrupts related to AUX channel */ 3963424e3a4SYakir Yang reg = RPLY_RECEIV | AUX_ERR; 397092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA); 3983424e3a4SYakir Yang 3993424e3a4SYakir Yang analogix_dp_reset_aux(dp); 4003424e3a4SYakir Yang 4013424e3a4SYakir Yang /* Disable AUX transaction H/W retry */ 4023424e3a4SYakir Yang reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) | AUX_HW_RETRY_COUNT_SEL(0) | 4033424e3a4SYakir Yang AUX_HW_RETRY_INTERVAL_600_MICROSECONDS; 404092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_AUX_HW_RETRY_CTL); 4053424e3a4SYakir Yang 4063424e3a4SYakir Yang /* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */ 4073424e3a4SYakir Yang reg = DEFER_CTRL_EN | DEFER_COUNT(1); 408092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_DEFER_CTL); 4093424e3a4SYakir Yang 4103424e3a4SYakir Yang /* Enable AUX channel module */ 411092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_2); 4123424e3a4SYakir Yang reg &= ~AUX_FUNC_EN_N; 413092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_2); 4143424e3a4SYakir Yang } 4153424e3a4SYakir Yang 4163424e3a4SYakir Yang int analogix_dp_get_plug_in_status(struct analogix_dp_device *dp) 4173424e3a4SYakir Yang { 4183424e3a4SYakir Yang u32 reg; 4193424e3a4SYakir Yang 4203424e3a4SYakir Yang if (gpio_is_valid(dp->hpd_gpio)) { 4213424e3a4SYakir Yang if (gpio_get_value(dp->hpd_gpio)) 4223424e3a4SYakir Yang return 0; 4233424e3a4SYakir Yang } else { 424092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_3); 4253424e3a4SYakir Yang if (reg & HPD_STATUS) 4263424e3a4SYakir Yang return 0; 4273424e3a4SYakir Yang } 4283424e3a4SYakir Yang 4293424e3a4SYakir Yang return -EINVAL; 4303424e3a4SYakir Yang } 4313424e3a4SYakir Yang 4323424e3a4SYakir Yang void analogix_dp_enable_sw_function(struct analogix_dp_device *dp) 4333424e3a4SYakir Yang { 4343424e3a4SYakir Yang u32 reg; 4353424e3a4SYakir Yang 436092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_1); 4373424e3a4SYakir Yang reg &= ~SW_FUNC_EN_N; 438092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_1); 4393424e3a4SYakir Yang } 4403424e3a4SYakir Yang 4413424e3a4SYakir Yang int analogix_dp_start_aux_transaction(struct analogix_dp_device *dp) 4423424e3a4SYakir Yang { 4433424e3a4SYakir Yang int reg; 4443424e3a4SYakir Yang int retval = 0; 4453424e3a4SYakir Yang int timeout_loop = 0; 4463424e3a4SYakir Yang 4473424e3a4SYakir Yang /* Enable AUX CH operation */ 448092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); 4493424e3a4SYakir Yang reg |= AUX_EN; 450092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); 4513424e3a4SYakir Yang 4523424e3a4SYakir Yang /* Is AUX CH command reply received? */ 453092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); 4543424e3a4SYakir Yang while (!(reg & RPLY_RECEIV)) { 4553424e3a4SYakir Yang timeout_loop++; 4563424e3a4SYakir Yang if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { 4573424e3a4SYakir Yang dev_err(dp->dev, "AUX CH command reply failed!\n"); 4583424e3a4SYakir Yang return -ETIMEDOUT; 4593424e3a4SYakir Yang } 460092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); 4613424e3a4SYakir Yang usleep_range(10, 11); 4623424e3a4SYakir Yang } 4633424e3a4SYakir Yang 4643424e3a4SYakir Yang /* Clear interrupt source for AUX CH command reply */ 465092f8994SHeiko Stuebner writel(RPLY_RECEIV, dp->reg_base + ANALOGIX_DP_INT_STA); 4663424e3a4SYakir Yang 4673424e3a4SYakir Yang /* Clear interrupt source for AUX CH access error */ 468092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); 4693424e3a4SYakir Yang if (reg & AUX_ERR) { 470092f8994SHeiko Stuebner writel(AUX_ERR, dp->reg_base + ANALOGIX_DP_INT_STA); 4713424e3a4SYakir Yang return -EREMOTEIO; 4723424e3a4SYakir Yang } 4733424e3a4SYakir Yang 4743424e3a4SYakir Yang /* Check AUX CH error access status */ 475092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_STA); 4763424e3a4SYakir Yang if ((reg & AUX_STATUS_MASK) != 0) { 4773424e3a4SYakir Yang dev_err(dp->dev, "AUX CH error happens: %d\n\n", 4783424e3a4SYakir Yang reg & AUX_STATUS_MASK); 4793424e3a4SYakir Yang return -EREMOTEIO; 4803424e3a4SYakir Yang } 4813424e3a4SYakir Yang 4823424e3a4SYakir Yang return retval; 4833424e3a4SYakir Yang } 4843424e3a4SYakir Yang 4853424e3a4SYakir Yang int analogix_dp_write_byte_to_dpcd(struct analogix_dp_device *dp, 4863424e3a4SYakir Yang unsigned int reg_addr, 4873424e3a4SYakir Yang unsigned char data) 4883424e3a4SYakir Yang { 4893424e3a4SYakir Yang u32 reg; 4903424e3a4SYakir Yang int i; 4913424e3a4SYakir Yang int retval; 4923424e3a4SYakir Yang 4933424e3a4SYakir Yang for (i = 0; i < 3; i++) { 4943424e3a4SYakir Yang /* Clear AUX CH data buffer */ 4953424e3a4SYakir Yang reg = BUF_CLR; 496092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); 4973424e3a4SYakir Yang 4983424e3a4SYakir Yang /* Select DPCD device address */ 4993424e3a4SYakir Yang reg = AUX_ADDR_7_0(reg_addr); 500092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); 5013424e3a4SYakir Yang reg = AUX_ADDR_15_8(reg_addr); 502092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); 5033424e3a4SYakir Yang reg = AUX_ADDR_19_16(reg_addr); 504092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); 5053424e3a4SYakir Yang 5063424e3a4SYakir Yang /* Write data buffer */ 5073424e3a4SYakir Yang reg = (unsigned int)data; 508092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_BUF_DATA_0); 5093424e3a4SYakir Yang 5103424e3a4SYakir Yang /* 5113424e3a4SYakir Yang * Set DisplayPort transaction and write 1 byte 5123424e3a4SYakir Yang * If bit 3 is 1, DisplayPort transaction. 5133424e3a4SYakir Yang * If Bit 3 is 0, I2C transaction. 5143424e3a4SYakir Yang */ 5153424e3a4SYakir Yang reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; 516092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); 5173424e3a4SYakir Yang 5183424e3a4SYakir Yang /* Start AUX transaction */ 5193424e3a4SYakir Yang retval = analogix_dp_start_aux_transaction(dp); 5203424e3a4SYakir Yang if (retval == 0) 5213424e3a4SYakir Yang break; 522bcbb7033SYakir Yang 523bcbb7033SYakir Yang dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__); 5243424e3a4SYakir Yang } 5253424e3a4SYakir Yang 5263424e3a4SYakir Yang return retval; 5273424e3a4SYakir Yang } 5283424e3a4SYakir Yang 5293424e3a4SYakir Yang int analogix_dp_read_byte_from_dpcd(struct analogix_dp_device *dp, 5303424e3a4SYakir Yang unsigned int reg_addr, 5313424e3a4SYakir Yang unsigned char *data) 5323424e3a4SYakir Yang { 5333424e3a4SYakir Yang u32 reg; 5343424e3a4SYakir Yang int i; 5353424e3a4SYakir Yang int retval; 5363424e3a4SYakir Yang 5373424e3a4SYakir Yang for (i = 0; i < 3; i++) { 5383424e3a4SYakir Yang /* Clear AUX CH data buffer */ 5393424e3a4SYakir Yang reg = BUF_CLR; 540092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); 5413424e3a4SYakir Yang 5423424e3a4SYakir Yang /* Select DPCD device address */ 5433424e3a4SYakir Yang reg = AUX_ADDR_7_0(reg_addr); 544092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); 5453424e3a4SYakir Yang reg = AUX_ADDR_15_8(reg_addr); 546092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); 5473424e3a4SYakir Yang reg = AUX_ADDR_19_16(reg_addr); 548092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); 5493424e3a4SYakir Yang 5503424e3a4SYakir Yang /* 5513424e3a4SYakir Yang * Set DisplayPort transaction and read 1 byte 5523424e3a4SYakir Yang * If bit 3 is 1, DisplayPort transaction. 5533424e3a4SYakir Yang * If Bit 3 is 0, I2C transaction. 5543424e3a4SYakir Yang */ 5553424e3a4SYakir Yang reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; 556092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); 5573424e3a4SYakir Yang 5583424e3a4SYakir Yang /* Start AUX transaction */ 5593424e3a4SYakir Yang retval = analogix_dp_start_aux_transaction(dp); 5603424e3a4SYakir Yang if (retval == 0) 5613424e3a4SYakir Yang break; 562bcbb7033SYakir Yang 563bcbb7033SYakir Yang dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__); 5643424e3a4SYakir Yang } 5653424e3a4SYakir Yang 5663424e3a4SYakir Yang /* Read data buffer */ 567092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0); 5683424e3a4SYakir Yang *data = (unsigned char)(reg & 0xff); 5693424e3a4SYakir Yang 5703424e3a4SYakir Yang return retval; 5713424e3a4SYakir Yang } 5723424e3a4SYakir Yang 5733424e3a4SYakir Yang int analogix_dp_write_bytes_to_dpcd(struct analogix_dp_device *dp, 5743424e3a4SYakir Yang unsigned int reg_addr, 5753424e3a4SYakir Yang unsigned int count, 5763424e3a4SYakir Yang unsigned char data[]) 5773424e3a4SYakir Yang { 5783424e3a4SYakir Yang u32 reg; 5793424e3a4SYakir Yang unsigned int start_offset; 5803424e3a4SYakir Yang unsigned int cur_data_count; 5813424e3a4SYakir Yang unsigned int cur_data_idx; 5823424e3a4SYakir Yang int i; 5833424e3a4SYakir Yang int retval = 0; 5843424e3a4SYakir Yang 5853424e3a4SYakir Yang /* Clear AUX CH data buffer */ 5863424e3a4SYakir Yang reg = BUF_CLR; 587092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); 5883424e3a4SYakir Yang 5893424e3a4SYakir Yang start_offset = 0; 5903424e3a4SYakir Yang while (start_offset < count) { 5913424e3a4SYakir Yang /* Buffer size of AUX CH is 16 * 4bytes */ 5923424e3a4SYakir Yang if ((count - start_offset) > 16) 5933424e3a4SYakir Yang cur_data_count = 16; 5943424e3a4SYakir Yang else 5953424e3a4SYakir Yang cur_data_count = count - start_offset; 5963424e3a4SYakir Yang 5973424e3a4SYakir Yang for (i = 0; i < 3; i++) { 5983424e3a4SYakir Yang /* Select DPCD device address */ 5993424e3a4SYakir Yang reg = AUX_ADDR_7_0(reg_addr + start_offset); 600092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); 6013424e3a4SYakir Yang reg = AUX_ADDR_15_8(reg_addr + start_offset); 602092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); 6033424e3a4SYakir Yang reg = AUX_ADDR_19_16(reg_addr + start_offset); 604092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); 6053424e3a4SYakir Yang 6063424e3a4SYakir Yang for (cur_data_idx = 0; cur_data_idx < cur_data_count; 6073424e3a4SYakir Yang cur_data_idx++) { 6083424e3a4SYakir Yang reg = data[start_offset + cur_data_idx]; 609bcbb7033SYakir Yang writel(reg, dp->reg_base + 610bcbb7033SYakir Yang ANALOGIX_DP_BUF_DATA_0 + 611bcbb7033SYakir Yang 4 * cur_data_idx); 6123424e3a4SYakir Yang } 6133424e3a4SYakir Yang 6143424e3a4SYakir Yang /* 6153424e3a4SYakir Yang * Set DisplayPort transaction and write 6163424e3a4SYakir Yang * If bit 3 is 1, DisplayPort transaction. 6173424e3a4SYakir Yang * If Bit 3 is 0, I2C transaction. 6183424e3a4SYakir Yang */ 6193424e3a4SYakir Yang reg = AUX_LENGTH(cur_data_count) | 6203424e3a4SYakir Yang AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; 621092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); 6223424e3a4SYakir Yang 6233424e3a4SYakir Yang /* Start AUX transaction */ 6243424e3a4SYakir Yang retval = analogix_dp_start_aux_transaction(dp); 6253424e3a4SYakir Yang if (retval == 0) 6263424e3a4SYakir Yang break; 627bcbb7033SYakir Yang 6283424e3a4SYakir Yang dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", 6293424e3a4SYakir Yang __func__); 6303424e3a4SYakir Yang } 6313424e3a4SYakir Yang 6323424e3a4SYakir Yang start_offset += cur_data_count; 6333424e3a4SYakir Yang } 6343424e3a4SYakir Yang 6353424e3a4SYakir Yang return retval; 6363424e3a4SYakir Yang } 6373424e3a4SYakir Yang 6383424e3a4SYakir Yang int analogix_dp_read_bytes_from_dpcd(struct analogix_dp_device *dp, 6393424e3a4SYakir Yang unsigned int reg_addr, 6403424e3a4SYakir Yang unsigned int count, 6413424e3a4SYakir Yang unsigned char data[]) 6423424e3a4SYakir Yang { 6433424e3a4SYakir Yang u32 reg; 6443424e3a4SYakir Yang unsigned int start_offset; 6453424e3a4SYakir Yang unsigned int cur_data_count; 6463424e3a4SYakir Yang unsigned int cur_data_idx; 6473424e3a4SYakir Yang int i; 6483424e3a4SYakir Yang int retval = 0; 6493424e3a4SYakir Yang 6503424e3a4SYakir Yang /* Clear AUX CH data buffer */ 6513424e3a4SYakir Yang reg = BUF_CLR; 652092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); 6533424e3a4SYakir Yang 6543424e3a4SYakir Yang start_offset = 0; 6553424e3a4SYakir Yang while (start_offset < count) { 6563424e3a4SYakir Yang /* Buffer size of AUX CH is 16 * 4bytes */ 6573424e3a4SYakir Yang if ((count - start_offset) > 16) 6583424e3a4SYakir Yang cur_data_count = 16; 6593424e3a4SYakir Yang else 6603424e3a4SYakir Yang cur_data_count = count - start_offset; 6613424e3a4SYakir Yang 6623424e3a4SYakir Yang /* AUX CH Request Transaction process */ 6633424e3a4SYakir Yang for (i = 0; i < 3; i++) { 6643424e3a4SYakir Yang /* Select DPCD device address */ 6653424e3a4SYakir Yang reg = AUX_ADDR_7_0(reg_addr + start_offset); 666092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); 6673424e3a4SYakir Yang reg = AUX_ADDR_15_8(reg_addr + start_offset); 668092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); 6693424e3a4SYakir Yang reg = AUX_ADDR_19_16(reg_addr + start_offset); 670092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); 6713424e3a4SYakir Yang 6723424e3a4SYakir Yang /* 6733424e3a4SYakir Yang * Set DisplayPort transaction and read 6743424e3a4SYakir Yang * If bit 3 is 1, DisplayPort transaction. 6753424e3a4SYakir Yang * If Bit 3 is 0, I2C transaction. 6763424e3a4SYakir Yang */ 6773424e3a4SYakir Yang reg = AUX_LENGTH(cur_data_count) | 6783424e3a4SYakir Yang AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; 679092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); 6803424e3a4SYakir Yang 6813424e3a4SYakir Yang /* Start AUX transaction */ 6823424e3a4SYakir Yang retval = analogix_dp_start_aux_transaction(dp); 6833424e3a4SYakir Yang if (retval == 0) 6843424e3a4SYakir Yang break; 685bcbb7033SYakir Yang 6863424e3a4SYakir Yang dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", 6873424e3a4SYakir Yang __func__); 6883424e3a4SYakir Yang } 6893424e3a4SYakir Yang 6903424e3a4SYakir Yang for (cur_data_idx = 0; cur_data_idx < cur_data_count; 6913424e3a4SYakir Yang cur_data_idx++) { 692092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0 6933424e3a4SYakir Yang + 4 * cur_data_idx); 6943424e3a4SYakir Yang data[start_offset + cur_data_idx] = 6953424e3a4SYakir Yang (unsigned char)reg; 6963424e3a4SYakir Yang } 6973424e3a4SYakir Yang 6983424e3a4SYakir Yang start_offset += cur_data_count; 6993424e3a4SYakir Yang } 7003424e3a4SYakir Yang 7013424e3a4SYakir Yang return retval; 7023424e3a4SYakir Yang } 7033424e3a4SYakir Yang 7043424e3a4SYakir Yang int analogix_dp_select_i2c_device(struct analogix_dp_device *dp, 7053424e3a4SYakir Yang unsigned int device_addr, 7063424e3a4SYakir Yang unsigned int reg_addr) 7073424e3a4SYakir Yang { 7083424e3a4SYakir Yang u32 reg; 7093424e3a4SYakir Yang int retval; 7103424e3a4SYakir Yang 7113424e3a4SYakir Yang /* Set EDID device address */ 7123424e3a4SYakir Yang reg = device_addr; 713092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); 714092f8994SHeiko Stuebner writel(0x0, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); 715092f8994SHeiko Stuebner writel(0x0, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); 7163424e3a4SYakir Yang 7173424e3a4SYakir Yang /* Set offset from base address of EDID device */ 718092f8994SHeiko Stuebner writel(reg_addr, dp->reg_base + ANALOGIX_DP_BUF_DATA_0); 7193424e3a4SYakir Yang 7203424e3a4SYakir Yang /* 7213424e3a4SYakir Yang * Set I2C transaction and write address 7223424e3a4SYakir Yang * If bit 3 is 1, DisplayPort transaction. 7233424e3a4SYakir Yang * If Bit 3 is 0, I2C transaction. 7243424e3a4SYakir Yang */ 7253424e3a4SYakir Yang reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT | 7263424e3a4SYakir Yang AUX_TX_COMM_WRITE; 727092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); 7283424e3a4SYakir Yang 7293424e3a4SYakir Yang /* Start AUX transaction */ 7303424e3a4SYakir Yang retval = analogix_dp_start_aux_transaction(dp); 7313424e3a4SYakir Yang if (retval != 0) 7323424e3a4SYakir Yang dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__); 7333424e3a4SYakir Yang 7343424e3a4SYakir Yang return retval; 7353424e3a4SYakir Yang } 7363424e3a4SYakir Yang 7373424e3a4SYakir Yang int analogix_dp_read_byte_from_i2c(struct analogix_dp_device *dp, 7383424e3a4SYakir Yang unsigned int device_addr, 7393424e3a4SYakir Yang unsigned int reg_addr, 7403424e3a4SYakir Yang unsigned int *data) 7413424e3a4SYakir Yang { 7423424e3a4SYakir Yang u32 reg; 7433424e3a4SYakir Yang int i; 7443424e3a4SYakir Yang int retval; 7453424e3a4SYakir Yang 7463424e3a4SYakir Yang for (i = 0; i < 3; i++) { 7473424e3a4SYakir Yang /* Clear AUX CH data buffer */ 7483424e3a4SYakir Yang reg = BUF_CLR; 749092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); 7503424e3a4SYakir Yang 7513424e3a4SYakir Yang /* Select EDID device */ 752bcbb7033SYakir Yang retval = analogix_dp_select_i2c_device(dp, device_addr, 753bcbb7033SYakir Yang reg_addr); 7543424e3a4SYakir Yang if (retval != 0) 7553424e3a4SYakir Yang continue; 7563424e3a4SYakir Yang 7573424e3a4SYakir Yang /* 7583424e3a4SYakir Yang * Set I2C transaction and read data 7593424e3a4SYakir Yang * If bit 3 is 1, DisplayPort transaction. 7603424e3a4SYakir Yang * If Bit 3 is 0, I2C transaction. 7613424e3a4SYakir Yang */ 7623424e3a4SYakir Yang reg = AUX_TX_COMM_I2C_TRANSACTION | 7633424e3a4SYakir Yang AUX_TX_COMM_READ; 764092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); 7653424e3a4SYakir Yang 7663424e3a4SYakir Yang /* Start AUX transaction */ 7673424e3a4SYakir Yang retval = analogix_dp_start_aux_transaction(dp); 7683424e3a4SYakir Yang if (retval == 0) 7693424e3a4SYakir Yang break; 770bcbb7033SYakir Yang 771bcbb7033SYakir Yang dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__); 7723424e3a4SYakir Yang } 7733424e3a4SYakir Yang 7743424e3a4SYakir Yang /* Read data */ 7753424e3a4SYakir Yang if (retval == 0) 776092f8994SHeiko Stuebner *data = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0); 7773424e3a4SYakir Yang 7783424e3a4SYakir Yang return retval; 7793424e3a4SYakir Yang } 7803424e3a4SYakir Yang 7813424e3a4SYakir Yang int analogix_dp_read_bytes_from_i2c(struct analogix_dp_device *dp, 7823424e3a4SYakir Yang unsigned int device_addr, 7833424e3a4SYakir Yang unsigned int reg_addr, 7843424e3a4SYakir Yang unsigned int count, 7853424e3a4SYakir Yang unsigned char edid[]) 7863424e3a4SYakir Yang { 7873424e3a4SYakir Yang u32 reg; 7883424e3a4SYakir Yang unsigned int i, j; 7893424e3a4SYakir Yang unsigned int cur_data_idx; 7903424e3a4SYakir Yang unsigned int defer = 0; 7913424e3a4SYakir Yang int retval = 0; 7923424e3a4SYakir Yang 7933424e3a4SYakir Yang for (i = 0; i < count; i += 16) { 7943424e3a4SYakir Yang for (j = 0; j < 3; j++) { 7953424e3a4SYakir Yang /* Clear AUX CH data buffer */ 7963424e3a4SYakir Yang reg = BUF_CLR; 797092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); 7983424e3a4SYakir Yang 7993424e3a4SYakir Yang /* Set normal AUX CH command */ 800092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); 8013424e3a4SYakir Yang reg &= ~ADDR_ONLY; 802092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); 8033424e3a4SYakir Yang 8043424e3a4SYakir Yang /* 8053424e3a4SYakir Yang * If Rx sends defer, Tx sends only reads 8063424e3a4SYakir Yang * request without sending address 8073424e3a4SYakir Yang */ 8083424e3a4SYakir Yang if (!defer) 8093424e3a4SYakir Yang retval = analogix_dp_select_i2c_device(dp, 8103424e3a4SYakir Yang device_addr, reg_addr + i); 8113424e3a4SYakir Yang else 8123424e3a4SYakir Yang defer = 0; 8133424e3a4SYakir Yang 8143424e3a4SYakir Yang if (retval == 0) { 8153424e3a4SYakir Yang /* 8163424e3a4SYakir Yang * Set I2C transaction and write data 8173424e3a4SYakir Yang * If bit 3 is 1, DisplayPort transaction. 8183424e3a4SYakir Yang * If Bit 3 is 0, I2C transaction. 8193424e3a4SYakir Yang */ 8203424e3a4SYakir Yang reg = AUX_LENGTH(16) | 8213424e3a4SYakir Yang AUX_TX_COMM_I2C_TRANSACTION | 8223424e3a4SYakir Yang AUX_TX_COMM_READ; 8233424e3a4SYakir Yang writel(reg, dp->reg_base + 824092f8994SHeiko Stuebner ANALOGIX_DP_AUX_CH_CTL_1); 8253424e3a4SYakir Yang 8263424e3a4SYakir Yang /* Start AUX transaction */ 8273424e3a4SYakir Yang retval = analogix_dp_start_aux_transaction(dp); 8283424e3a4SYakir Yang if (retval == 0) 8293424e3a4SYakir Yang break; 830bcbb7033SYakir Yang 831bcbb7033SYakir Yang dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", 8323424e3a4SYakir Yang __func__); 8333424e3a4SYakir Yang } 8343424e3a4SYakir Yang /* Check if Rx sends defer */ 835092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_AUX_RX_COMM); 8363424e3a4SYakir Yang if (reg == AUX_RX_COMM_AUX_DEFER || 8373424e3a4SYakir Yang reg == AUX_RX_COMM_I2C_DEFER) { 8383424e3a4SYakir Yang dev_err(dp->dev, "Defer: %d\n\n", reg); 8393424e3a4SYakir Yang defer = 1; 8403424e3a4SYakir Yang } 8413424e3a4SYakir Yang } 8423424e3a4SYakir Yang 8433424e3a4SYakir Yang for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) { 844092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0 8453424e3a4SYakir Yang + 4 * cur_data_idx); 8463424e3a4SYakir Yang edid[i + cur_data_idx] = (unsigned char)reg; 8473424e3a4SYakir Yang } 8483424e3a4SYakir Yang } 8493424e3a4SYakir Yang 8503424e3a4SYakir Yang return retval; 8513424e3a4SYakir Yang } 8523424e3a4SYakir Yang 8533424e3a4SYakir Yang void analogix_dp_set_link_bandwidth(struct analogix_dp_device *dp, u32 bwtype) 8543424e3a4SYakir Yang { 8553424e3a4SYakir Yang u32 reg; 8563424e3a4SYakir Yang 8573424e3a4SYakir Yang reg = bwtype; 8583424e3a4SYakir Yang if ((bwtype == LINK_RATE_2_70GBPS) || (bwtype == LINK_RATE_1_62GBPS)) 859092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_LINK_BW_SET); 8603424e3a4SYakir Yang } 8613424e3a4SYakir Yang 8623424e3a4SYakir Yang void analogix_dp_get_link_bandwidth(struct analogix_dp_device *dp, u32 *bwtype) 8633424e3a4SYakir Yang { 8643424e3a4SYakir Yang u32 reg; 8653424e3a4SYakir Yang 866092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_LINK_BW_SET); 8673424e3a4SYakir Yang *bwtype = reg; 8683424e3a4SYakir Yang } 8693424e3a4SYakir Yang 8703424e3a4SYakir Yang void analogix_dp_set_lane_count(struct analogix_dp_device *dp, u32 count) 8713424e3a4SYakir Yang { 8723424e3a4SYakir Yang u32 reg; 8733424e3a4SYakir Yang 8743424e3a4SYakir Yang reg = count; 875092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_LANE_COUNT_SET); 8763424e3a4SYakir Yang } 8773424e3a4SYakir Yang 8783424e3a4SYakir Yang void analogix_dp_get_lane_count(struct analogix_dp_device *dp, u32 *count) 8793424e3a4SYakir Yang { 8803424e3a4SYakir Yang u32 reg; 8813424e3a4SYakir Yang 882092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_LANE_COUNT_SET); 8833424e3a4SYakir Yang *count = reg; 8843424e3a4SYakir Yang } 8853424e3a4SYakir Yang 886bcbb7033SYakir Yang void analogix_dp_enable_enhanced_mode(struct analogix_dp_device *dp, 887bcbb7033SYakir Yang bool enable) 8883424e3a4SYakir Yang { 8893424e3a4SYakir Yang u32 reg; 8903424e3a4SYakir Yang 8913424e3a4SYakir Yang if (enable) { 892092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_4); 8933424e3a4SYakir Yang reg |= ENHANCED; 894092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_4); 8953424e3a4SYakir Yang } else { 896092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_4); 8973424e3a4SYakir Yang reg &= ~ENHANCED; 898092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_4); 8993424e3a4SYakir Yang } 9003424e3a4SYakir Yang } 9013424e3a4SYakir Yang 9023424e3a4SYakir Yang void analogix_dp_set_training_pattern(struct analogix_dp_device *dp, 9033424e3a4SYakir Yang enum pattern_set pattern) 9043424e3a4SYakir Yang { 9053424e3a4SYakir Yang u32 reg; 9063424e3a4SYakir Yang 9073424e3a4SYakir Yang switch (pattern) { 9083424e3a4SYakir Yang case PRBS7: 9093424e3a4SYakir Yang reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7; 910092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); 9113424e3a4SYakir Yang break; 9123424e3a4SYakir Yang case D10_2: 9133424e3a4SYakir Yang reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2; 914092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); 9153424e3a4SYakir Yang break; 9163424e3a4SYakir Yang case TRAINING_PTN1: 9173424e3a4SYakir Yang reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1; 918092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); 9193424e3a4SYakir Yang break; 9203424e3a4SYakir Yang case TRAINING_PTN2: 9213424e3a4SYakir Yang reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2; 922092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); 9233424e3a4SYakir Yang break; 9243424e3a4SYakir Yang case DP_NONE: 9253424e3a4SYakir Yang reg = SCRAMBLING_ENABLE | 9263424e3a4SYakir Yang LINK_QUAL_PATTERN_SET_DISABLE | 9273424e3a4SYakir Yang SW_TRAINING_PATTERN_SET_NORMAL; 928092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); 9293424e3a4SYakir Yang break; 9303424e3a4SYakir Yang default: 9313424e3a4SYakir Yang break; 9323424e3a4SYakir Yang } 9333424e3a4SYakir Yang } 9343424e3a4SYakir Yang 935bcbb7033SYakir Yang void analogix_dp_set_lane0_pre_emphasis(struct analogix_dp_device *dp, 936bcbb7033SYakir Yang u32 level) 9373424e3a4SYakir Yang { 9383424e3a4SYakir Yang u32 reg; 9393424e3a4SYakir Yang 940092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL); 9413424e3a4SYakir Yang reg &= ~PRE_EMPHASIS_SET_MASK; 9423424e3a4SYakir Yang reg |= level << PRE_EMPHASIS_SET_SHIFT; 943092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL); 9443424e3a4SYakir Yang } 9453424e3a4SYakir Yang 946bcbb7033SYakir Yang void analogix_dp_set_lane1_pre_emphasis(struct analogix_dp_device *dp, 947bcbb7033SYakir Yang u32 level) 9483424e3a4SYakir Yang { 9493424e3a4SYakir Yang u32 reg; 9503424e3a4SYakir Yang 951092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL); 9523424e3a4SYakir Yang reg &= ~PRE_EMPHASIS_SET_MASK; 9533424e3a4SYakir Yang reg |= level << PRE_EMPHASIS_SET_SHIFT; 954092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL); 9553424e3a4SYakir Yang } 9563424e3a4SYakir Yang 957bcbb7033SYakir Yang void analogix_dp_set_lane2_pre_emphasis(struct analogix_dp_device *dp, 958bcbb7033SYakir Yang u32 level) 9593424e3a4SYakir Yang { 9603424e3a4SYakir Yang u32 reg; 9613424e3a4SYakir Yang 962092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL); 9633424e3a4SYakir Yang reg &= ~PRE_EMPHASIS_SET_MASK; 9643424e3a4SYakir Yang reg |= level << PRE_EMPHASIS_SET_SHIFT; 965092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL); 9663424e3a4SYakir Yang } 9673424e3a4SYakir Yang 968bcbb7033SYakir Yang void analogix_dp_set_lane3_pre_emphasis(struct analogix_dp_device *dp, 969bcbb7033SYakir Yang u32 level) 9703424e3a4SYakir Yang { 9713424e3a4SYakir Yang u32 reg; 9723424e3a4SYakir Yang 973092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL); 9743424e3a4SYakir Yang reg &= ~PRE_EMPHASIS_SET_MASK; 9753424e3a4SYakir Yang reg |= level << PRE_EMPHASIS_SET_SHIFT; 976092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL); 9773424e3a4SYakir Yang } 9783424e3a4SYakir Yang 9793424e3a4SYakir Yang void analogix_dp_set_lane0_link_training(struct analogix_dp_device *dp, 9803424e3a4SYakir Yang u32 training_lane) 9813424e3a4SYakir Yang { 9823424e3a4SYakir Yang u32 reg; 9833424e3a4SYakir Yang 9843424e3a4SYakir Yang reg = training_lane; 985092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL); 9863424e3a4SYakir Yang } 9873424e3a4SYakir Yang 9883424e3a4SYakir Yang void analogix_dp_set_lane1_link_training(struct analogix_dp_device *dp, 9893424e3a4SYakir Yang u32 training_lane) 9903424e3a4SYakir Yang { 9913424e3a4SYakir Yang u32 reg; 9923424e3a4SYakir Yang 9933424e3a4SYakir Yang reg = training_lane; 994092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL); 9953424e3a4SYakir Yang } 9963424e3a4SYakir Yang 9973424e3a4SYakir Yang void analogix_dp_set_lane2_link_training(struct analogix_dp_device *dp, 9983424e3a4SYakir Yang u32 training_lane) 9993424e3a4SYakir Yang { 10003424e3a4SYakir Yang u32 reg; 10013424e3a4SYakir Yang 10023424e3a4SYakir Yang reg = training_lane; 1003092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL); 10043424e3a4SYakir Yang } 10053424e3a4SYakir Yang 10063424e3a4SYakir Yang void analogix_dp_set_lane3_link_training(struct analogix_dp_device *dp, 10073424e3a4SYakir Yang u32 training_lane) 10083424e3a4SYakir Yang { 10093424e3a4SYakir Yang u32 reg; 10103424e3a4SYakir Yang 10113424e3a4SYakir Yang reg = training_lane; 1012092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL); 10133424e3a4SYakir Yang } 10143424e3a4SYakir Yang 10153424e3a4SYakir Yang u32 analogix_dp_get_lane0_link_training(struct analogix_dp_device *dp) 10163424e3a4SYakir Yang { 10173424e3a4SYakir Yang u32 reg; 10183424e3a4SYakir Yang 1019092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL); 10203424e3a4SYakir Yang return reg; 10213424e3a4SYakir Yang } 10223424e3a4SYakir Yang 10233424e3a4SYakir Yang u32 analogix_dp_get_lane1_link_training(struct analogix_dp_device *dp) 10243424e3a4SYakir Yang { 10253424e3a4SYakir Yang u32 reg; 10263424e3a4SYakir Yang 1027092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL); 10283424e3a4SYakir Yang return reg; 10293424e3a4SYakir Yang } 10303424e3a4SYakir Yang 10313424e3a4SYakir Yang u32 analogix_dp_get_lane2_link_training(struct analogix_dp_device *dp) 10323424e3a4SYakir Yang { 10333424e3a4SYakir Yang u32 reg; 10343424e3a4SYakir Yang 1035092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL); 10363424e3a4SYakir Yang return reg; 10373424e3a4SYakir Yang } 10383424e3a4SYakir Yang 10393424e3a4SYakir Yang u32 analogix_dp_get_lane3_link_training(struct analogix_dp_device *dp) 10403424e3a4SYakir Yang { 10413424e3a4SYakir Yang u32 reg; 10423424e3a4SYakir Yang 1043092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL); 10443424e3a4SYakir Yang return reg; 10453424e3a4SYakir Yang } 10463424e3a4SYakir Yang 10473424e3a4SYakir Yang void analogix_dp_reset_macro(struct analogix_dp_device *dp) 10483424e3a4SYakir Yang { 10493424e3a4SYakir Yang u32 reg; 10503424e3a4SYakir Yang 1051092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_PHY_TEST); 10523424e3a4SYakir Yang reg |= MACRO_RST; 1053092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_PHY_TEST); 10543424e3a4SYakir Yang 10553424e3a4SYakir Yang /* 10 us is the minimum reset time. */ 10563424e3a4SYakir Yang usleep_range(10, 20); 10573424e3a4SYakir Yang 10583424e3a4SYakir Yang reg &= ~MACRO_RST; 1059092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_PHY_TEST); 10603424e3a4SYakir Yang } 10613424e3a4SYakir Yang 10623424e3a4SYakir Yang void analogix_dp_init_video(struct analogix_dp_device *dp) 10633424e3a4SYakir Yang { 10643424e3a4SYakir Yang u32 reg; 10653424e3a4SYakir Yang 10663424e3a4SYakir Yang reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG; 1067092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_1); 10683424e3a4SYakir Yang 10693424e3a4SYakir Yang reg = 0x0; 1070092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_1); 10713424e3a4SYakir Yang 10723424e3a4SYakir Yang reg = CHA_CRI(4) | CHA_CTRL; 1073092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_2); 10743424e3a4SYakir Yang 10753424e3a4SYakir Yang reg = 0x0; 1076092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_3); 10773424e3a4SYakir Yang 10783424e3a4SYakir Yang reg = VID_HRES_TH(2) | VID_VRES_TH(0); 1079092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_8); 10803424e3a4SYakir Yang } 10813424e3a4SYakir Yang 10823424e3a4SYakir Yang void analogix_dp_set_video_color_format(struct analogix_dp_device *dp) 10833424e3a4SYakir Yang { 10843424e3a4SYakir Yang u32 reg; 10853424e3a4SYakir Yang 10863424e3a4SYakir Yang /* Configure the input color depth, color space, dynamic range */ 10873424e3a4SYakir Yang reg = (dp->video_info->dynamic_range << IN_D_RANGE_SHIFT) | 10883424e3a4SYakir Yang (dp->video_info->color_depth << IN_BPC_SHIFT) | 10893424e3a4SYakir Yang (dp->video_info->color_space << IN_COLOR_F_SHIFT); 1090092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_2); 10913424e3a4SYakir Yang 10923424e3a4SYakir Yang /* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */ 1093092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_3); 10943424e3a4SYakir Yang reg &= ~IN_YC_COEFFI_MASK; 10953424e3a4SYakir Yang if (dp->video_info->ycbcr_coeff) 10963424e3a4SYakir Yang reg |= IN_YC_COEFFI_ITU709; 10973424e3a4SYakir Yang else 10983424e3a4SYakir Yang reg |= IN_YC_COEFFI_ITU601; 1099092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_3); 11003424e3a4SYakir Yang } 11013424e3a4SYakir Yang 11023424e3a4SYakir Yang int analogix_dp_is_slave_video_stream_clock_on(struct analogix_dp_device *dp) 11033424e3a4SYakir Yang { 11043424e3a4SYakir Yang u32 reg; 11053424e3a4SYakir Yang 1106092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_1); 1107092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_1); 11083424e3a4SYakir Yang 1109092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_1); 11103424e3a4SYakir Yang 11113424e3a4SYakir Yang if (!(reg & DET_STA)) { 11123424e3a4SYakir Yang dev_dbg(dp->dev, "Input stream clock not detected.\n"); 11133424e3a4SYakir Yang return -EINVAL; 11143424e3a4SYakir Yang } 11153424e3a4SYakir Yang 1116092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_2); 1117092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_2); 11183424e3a4SYakir Yang 1119092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_2); 11203424e3a4SYakir Yang dev_dbg(dp->dev, "wait SYS_CTL_2.\n"); 11213424e3a4SYakir Yang 11223424e3a4SYakir Yang if (reg & CHA_STA) { 11233424e3a4SYakir Yang dev_dbg(dp->dev, "Input stream clk is changing\n"); 11243424e3a4SYakir Yang return -EINVAL; 11253424e3a4SYakir Yang } 11263424e3a4SYakir Yang 11273424e3a4SYakir Yang return 0; 11283424e3a4SYakir Yang } 11293424e3a4SYakir Yang 11303424e3a4SYakir Yang void analogix_dp_set_video_cr_mn(struct analogix_dp_device *dp, 11313424e3a4SYakir Yang enum clock_recovery_m_value_type type, 1132bcbb7033SYakir Yang u32 m_value, u32 n_value) 11333424e3a4SYakir Yang { 11343424e3a4SYakir Yang u32 reg; 11353424e3a4SYakir Yang 11363424e3a4SYakir Yang if (type == REGISTER_M) { 1137092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_4); 11383424e3a4SYakir Yang reg |= FIX_M_VID; 1139092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_4); 11403424e3a4SYakir Yang reg = m_value & 0xff; 1141092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_M_VID_0); 11423424e3a4SYakir Yang reg = (m_value >> 8) & 0xff; 1143092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_M_VID_1); 11443424e3a4SYakir Yang reg = (m_value >> 16) & 0xff; 1145092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_M_VID_2); 11463424e3a4SYakir Yang 11473424e3a4SYakir Yang reg = n_value & 0xff; 1148092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_N_VID_0); 11493424e3a4SYakir Yang reg = (n_value >> 8) & 0xff; 1150092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_N_VID_1); 11513424e3a4SYakir Yang reg = (n_value >> 16) & 0xff; 1152092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_N_VID_2); 11533424e3a4SYakir Yang } else { 1154092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_4); 11553424e3a4SYakir Yang reg &= ~FIX_M_VID; 1156092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_4); 11573424e3a4SYakir Yang 1158092f8994SHeiko Stuebner writel(0x00, dp->reg_base + ANALOGIX_DP_N_VID_0); 1159092f8994SHeiko Stuebner writel(0x80, dp->reg_base + ANALOGIX_DP_N_VID_1); 1160092f8994SHeiko Stuebner writel(0x00, dp->reg_base + ANALOGIX_DP_N_VID_2); 11613424e3a4SYakir Yang } 11623424e3a4SYakir Yang } 11633424e3a4SYakir Yang 11643424e3a4SYakir Yang void analogix_dp_set_video_timing_mode(struct analogix_dp_device *dp, u32 type) 11653424e3a4SYakir Yang { 11663424e3a4SYakir Yang u32 reg; 11673424e3a4SYakir Yang 11683424e3a4SYakir Yang if (type == VIDEO_TIMING_FROM_CAPTURE) { 1169092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); 11703424e3a4SYakir Yang reg &= ~FORMAT_SEL; 1171092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); 11723424e3a4SYakir Yang } else { 1173092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); 11743424e3a4SYakir Yang reg |= FORMAT_SEL; 1175092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); 11763424e3a4SYakir Yang } 11773424e3a4SYakir Yang } 11783424e3a4SYakir Yang 11793424e3a4SYakir Yang void analogix_dp_enable_video_master(struct analogix_dp_device *dp, bool enable) 11803424e3a4SYakir Yang { 11813424e3a4SYakir Yang u32 reg; 11823424e3a4SYakir Yang 11833424e3a4SYakir Yang if (enable) { 1184092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL); 11853424e3a4SYakir Yang reg &= ~VIDEO_MODE_MASK; 11863424e3a4SYakir Yang reg |= VIDEO_MASTER_MODE_EN | VIDEO_MODE_MASTER_MODE; 1187092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL); 11883424e3a4SYakir Yang } else { 1189092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL); 11903424e3a4SYakir Yang reg &= ~VIDEO_MODE_MASK; 11913424e3a4SYakir Yang reg |= VIDEO_MODE_SLAVE_MODE; 1192092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL); 11933424e3a4SYakir Yang } 11943424e3a4SYakir Yang } 11953424e3a4SYakir Yang 11963424e3a4SYakir Yang void analogix_dp_start_video(struct analogix_dp_device *dp) 11973424e3a4SYakir Yang { 11983424e3a4SYakir Yang u32 reg; 11993424e3a4SYakir Yang 1200092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); 12013424e3a4SYakir Yang reg |= VIDEO_EN; 1202092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); 12033424e3a4SYakir Yang } 12043424e3a4SYakir Yang 12053424e3a4SYakir Yang int analogix_dp_is_video_stream_on(struct analogix_dp_device *dp) 12063424e3a4SYakir Yang { 12073424e3a4SYakir Yang u32 reg; 12083424e3a4SYakir Yang 1209092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_3); 1210092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_3); 12113424e3a4SYakir Yang 1212092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_3); 12133424e3a4SYakir Yang if (!(reg & STRM_VALID)) { 12143424e3a4SYakir Yang dev_dbg(dp->dev, "Input video stream is not detected.\n"); 12153424e3a4SYakir Yang return -EINVAL; 12163424e3a4SYakir Yang } 12173424e3a4SYakir Yang 12183424e3a4SYakir Yang return 0; 12193424e3a4SYakir Yang } 12203424e3a4SYakir Yang 12213424e3a4SYakir Yang void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp) 12223424e3a4SYakir Yang { 12233424e3a4SYakir Yang u32 reg; 12243424e3a4SYakir Yang 1225092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_1); 12263424e3a4SYakir Yang reg &= ~(MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N); 12273424e3a4SYakir Yang reg |= MASTER_VID_FUNC_EN_N; 1228092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_1); 12293424e3a4SYakir Yang 1230092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); 12313424e3a4SYakir Yang reg &= ~INTERACE_SCAN_CFG; 12323424e3a4SYakir Yang reg |= (dp->video_info->interlaced << 2); 1233092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); 12343424e3a4SYakir Yang 1235092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); 12363424e3a4SYakir Yang reg &= ~VSYNC_POLARITY_CFG; 12373424e3a4SYakir Yang reg |= (dp->video_info->v_sync_polarity << 1); 1238092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); 12393424e3a4SYakir Yang 1240092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); 12413424e3a4SYakir Yang reg &= ~HSYNC_POLARITY_CFG; 12423424e3a4SYakir Yang reg |= (dp->video_info->h_sync_polarity << 0); 1243092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); 12443424e3a4SYakir Yang 12453424e3a4SYakir Yang reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE; 1246092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL); 12473424e3a4SYakir Yang } 12483424e3a4SYakir Yang 12493424e3a4SYakir Yang void analogix_dp_enable_scrambling(struct analogix_dp_device *dp) 12503424e3a4SYakir Yang { 12513424e3a4SYakir Yang u32 reg; 12523424e3a4SYakir Yang 1253092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); 12543424e3a4SYakir Yang reg &= ~SCRAMBLING_DISABLE; 1255092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); 12563424e3a4SYakir Yang } 12573424e3a4SYakir Yang 12583424e3a4SYakir Yang void analogix_dp_disable_scrambling(struct analogix_dp_device *dp) 12593424e3a4SYakir Yang { 12603424e3a4SYakir Yang u32 reg; 12613424e3a4SYakir Yang 1262092f8994SHeiko Stuebner reg = readl(dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); 12633424e3a4SYakir Yang reg |= SCRAMBLING_DISABLE; 1264092f8994SHeiko Stuebner writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); 12653424e3a4SYakir Yang } 1266