Path: blob/master/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
26516 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* Analogix DP (Display port) core register interface driver.3*4* Copyright (C) 2012 Samsung Electronics Co., Ltd.5* Author: Jingoo Han <[email protected]>6*/78#include <linux/delay.h>9#include <linux/device.h>10#include <linux/gpio/consumer.h>11#include <linux/io.h>12#include <linux/iopoll.h>13#include <linux/phy/phy.h>1415#include <drm/bridge/analogix_dp.h>1617#include "analogix_dp_core.h"18#include "analogix_dp_reg.h"1920#define COMMON_INT_MASK_1 021#define COMMON_INT_MASK_2 022#define COMMON_INT_MASK_3 023#define COMMON_INT_MASK_4 (HOTPLUG_CHG | HPD_LOST | PLUG)24#define INT_STA_MASK INT_HPD2526void analogix_dp_enable_video_mute(struct analogix_dp_device *dp, bool enable)27{28u32 reg;2930if (enable) {31reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1);32reg |= HDCP_VIDEO_MUTE;33writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1);34} else {35reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1);36reg &= ~HDCP_VIDEO_MUTE;37writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1);38}39}4041void analogix_dp_stop_video(struct analogix_dp_device *dp)42{43u32 reg;4445reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1);46reg &= ~VIDEO_EN;47writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1);48}4950void analogix_dp_lane_swap(struct analogix_dp_device *dp, bool enable)51{52u32 reg;5354if (enable)55reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 |56LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3;57else58reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 |59LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0;6061writel(reg, dp->reg_base + ANALOGIX_DP_LANE_MAP);62}6364void analogix_dp_init_analog_param(struct analogix_dp_device *dp)65{66u32 reg;6768reg = TX_TERMINAL_CTRL_50_OHM;69writel(reg, dp->reg_base + ANALOGIX_DP_ANALOG_CTL_1);7071reg = SEL_24M | TX_DVDD_BIT_1_0625V;72writel(reg, dp->reg_base + ANALOGIX_DP_ANALOG_CTL_2);7374if (dp->plat_data && is_rockchip(dp->plat_data->dev_type)) {75reg = REF_CLK_24M;76if (dp->plat_data->dev_type == RK3288_DP)77reg ^= REF_CLK_MASK;7879writel(reg, dp->reg_base + ANALOGIX_DP_PLL_REG_1);80writel(0x95, dp->reg_base + ANALOGIX_DP_PLL_REG_2);81writel(0x40, dp->reg_base + ANALOGIX_DP_PLL_REG_3);82writel(0x58, dp->reg_base + ANALOGIX_DP_PLL_REG_4);83writel(0x22, dp->reg_base + ANALOGIX_DP_PLL_REG_5);84}8586reg = DRIVE_DVDD_BIT_1_0625V | VCO_BIT_600_MICRO;87writel(reg, dp->reg_base + ANALOGIX_DP_ANALOG_CTL_3);8889reg = PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM |90TX_CUR1_2X | TX_CUR_16_MA;91writel(reg, dp->reg_base + ANALOGIX_DP_PLL_FILTER_CTL_1);9293reg = CH3_AMP_400_MV | CH2_AMP_400_MV |94CH1_AMP_400_MV | CH0_AMP_400_MV;95writel(reg, dp->reg_base + ANALOGIX_DP_TX_AMP_TUNING_CTL);96}9798void analogix_dp_init_interrupt(struct analogix_dp_device *dp)99{100/* Set interrupt pin assertion polarity as high */101writel(INT_POL1 | INT_POL0, dp->reg_base + ANALOGIX_DP_INT_CTL);102103/* Clear pending regisers */104writel(0xff, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_1);105writel(0x4f, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_2);106writel(0xe0, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_3);107writel(0xe7, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_4);108writel(0x63, dp->reg_base + ANALOGIX_DP_INT_STA);109110/* 0:mask,1: unmask */111writel(0x00, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_1);112writel(0x00, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_2);113writel(0x00, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_3);114writel(0x00, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4);115writel(0x00, dp->reg_base + ANALOGIX_DP_INT_STA_MASK);116}117118void analogix_dp_reset(struct analogix_dp_device *dp)119{120u32 reg;121122analogix_dp_stop_video(dp);123analogix_dp_enable_video_mute(dp, 0);124125if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))126reg = RK_VID_CAP_FUNC_EN_N | RK_VID_FIFO_FUNC_EN_N |127SW_FUNC_EN_N;128else129reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N |130AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N |131HDCP_FUNC_EN_N | SW_FUNC_EN_N;132133writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_1);134135reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N |136SERDES_FIFO_FUNC_EN_N |137LS_CLK_DOMAIN_FUNC_EN_N;138writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_2);139140usleep_range(20, 30);141142analogix_dp_lane_swap(dp, 0);143144writel(0x0, dp->reg_base + ANALOGIX_DP_SYS_CTL_1);145writel(0x40, dp->reg_base + ANALOGIX_DP_SYS_CTL_2);146writel(0x0, dp->reg_base + ANALOGIX_DP_SYS_CTL_3);147writel(0x0, dp->reg_base + ANALOGIX_DP_SYS_CTL_4);148149writel(0x0, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);150writel(0x0, dp->reg_base + ANALOGIX_DP_HDCP_CTL);151152writel(0x5e, dp->reg_base + ANALOGIX_DP_HPD_DEGLITCH_L);153writel(0x1a, dp->reg_base + ANALOGIX_DP_HPD_DEGLITCH_H);154155writel(0x10, dp->reg_base + ANALOGIX_DP_LINK_DEBUG_CTL);156157writel(0x0, dp->reg_base + ANALOGIX_DP_PHY_TEST);158159writel(0x0, dp->reg_base + ANALOGIX_DP_VIDEO_FIFO_THRD);160writel(0x20, dp->reg_base + ANALOGIX_DP_AUDIO_MARGIN);161162writel(0x4, dp->reg_base + ANALOGIX_DP_M_VID_GEN_FILTER_TH);163writel(0x2, dp->reg_base + ANALOGIX_DP_M_AUD_GEN_FILTER_TH);164165writel(0x00000101, dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL);166}167168void analogix_dp_swreset(struct analogix_dp_device *dp)169{170writel(RESET_DP_TX, dp->reg_base + ANALOGIX_DP_TX_SW_RESET);171}172173void analogix_dp_config_interrupt(struct analogix_dp_device *dp)174{175u32 reg;176177/* 0: mask, 1: unmask */178reg = COMMON_INT_MASK_1;179writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_1);180181reg = COMMON_INT_MASK_2;182writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_2);183184reg = COMMON_INT_MASK_3;185writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_3);186187reg = COMMON_INT_MASK_4;188writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4);189190reg = INT_STA_MASK;191writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA_MASK);192}193194void analogix_dp_mute_hpd_interrupt(struct analogix_dp_device *dp)195{196u32 reg;197198/* 0: mask, 1: unmask */199reg = readl(dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4);200reg &= ~COMMON_INT_MASK_4;201writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4);202203reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA_MASK);204reg &= ~INT_STA_MASK;205writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA_MASK);206}207208void analogix_dp_unmute_hpd_interrupt(struct analogix_dp_device *dp)209{210u32 reg;211212/* 0: mask, 1: unmask */213reg = COMMON_INT_MASK_4;214writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4);215216reg = INT_STA_MASK;217writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA_MASK);218}219220int analogix_dp_wait_pll_locked(struct analogix_dp_device *dp)221{222u32 val;223224return readl_poll_timeout(dp->reg_base + ANALOGIX_DP_DEBUG_CTL, val,225val & PLL_LOCK, 120,226120 * DP_TIMEOUT_LOOP_COUNT);227}228229void analogix_dp_set_pll_power_down(struct analogix_dp_device *dp, bool enable)230{231u32 reg;232u32 mask = DP_PLL_PD;233u32 pd_addr = ANALOGIX_DP_PLL_CTL;234235if (dp->plat_data && is_rockchip(dp->plat_data->dev_type)) {236pd_addr = ANALOGIX_DP_PD;237mask = RK_PLL_PD;238}239240reg = readl(dp->reg_base + pd_addr);241if (enable)242reg |= mask;243else244reg &= ~mask;245writel(reg, dp->reg_base + pd_addr);246}247248void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp,249enum analog_power_block block,250bool enable)251{252u32 reg;253u32 phy_pd_addr = ANALOGIX_DP_PHY_PD;254u32 mask;255256if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))257phy_pd_addr = ANALOGIX_DP_PD;258259switch (block) {260case AUX_BLOCK:261if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))262mask = RK_AUX_PD;263else264mask = AUX_PD;265266reg = readl(dp->reg_base + phy_pd_addr);267if (enable)268reg |= mask;269else270reg &= ~mask;271writel(reg, dp->reg_base + phy_pd_addr);272break;273case CH0_BLOCK:274mask = CH0_PD;275reg = readl(dp->reg_base + phy_pd_addr);276277if (enable)278reg |= mask;279else280reg &= ~mask;281writel(reg, dp->reg_base + phy_pd_addr);282break;283case CH1_BLOCK:284mask = CH1_PD;285reg = readl(dp->reg_base + phy_pd_addr);286287if (enable)288reg |= mask;289else290reg &= ~mask;291writel(reg, dp->reg_base + phy_pd_addr);292break;293case CH2_BLOCK:294mask = CH2_PD;295reg = readl(dp->reg_base + phy_pd_addr);296297if (enable)298reg |= mask;299else300reg &= ~mask;301writel(reg, dp->reg_base + phy_pd_addr);302break;303case CH3_BLOCK:304mask = CH3_PD;305reg = readl(dp->reg_base + phy_pd_addr);306307if (enable)308reg |= mask;309else310reg &= ~mask;311writel(reg, dp->reg_base + phy_pd_addr);312break;313case ANALOG_TOTAL:314/*315* There is no bit named DP_PHY_PD, so We used DP_INC_BG316* to power off everything instead of DP_PHY_PD in317* Rockchip318*/319if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))320mask = DP_INC_BG;321else322mask = DP_PHY_PD;323324reg = readl(dp->reg_base + phy_pd_addr);325if (enable)326reg |= mask;327else328reg &= ~mask;329330writel(reg, dp->reg_base + phy_pd_addr);331if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))332usleep_range(10, 15);333break;334case POWER_ALL:335if (enable) {336reg = DP_ALL_PD;337writel(reg, dp->reg_base + phy_pd_addr);338} else {339reg = DP_ALL_PD;340writel(reg, dp->reg_base + phy_pd_addr);341usleep_range(10, 15);342reg &= ~DP_INC_BG;343writel(reg, dp->reg_base + phy_pd_addr);344usleep_range(10, 15);345346writel(0x00, dp->reg_base + phy_pd_addr);347}348break;349default:350break;351}352}353354int analogix_dp_init_analog_func(struct analogix_dp_device *dp)355{356u32 reg;357358analogix_dp_set_analog_power_down(dp, POWER_ALL, 0);359360reg = PLL_LOCK_CHG;361writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_1);362363reg = readl(dp->reg_base + ANALOGIX_DP_DEBUG_CTL);364reg &= ~(F_PLL_LOCK | PLL_LOCK_CTRL);365writel(reg, dp->reg_base + ANALOGIX_DP_DEBUG_CTL);366367/* Power up PLL */368analogix_dp_set_pll_power_down(dp, 0);369370/* Enable Serdes FIFO function and Link symbol clock domain module */371reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_2);372reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N373| AUX_FUNC_EN_N);374writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_2);375return 0;376}377378void analogix_dp_clear_hotplug_interrupts(struct analogix_dp_device *dp)379{380u32 reg;381382if (dp->hpd_gpiod)383return;384385reg = HOTPLUG_CHG | HPD_LOST | PLUG;386writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_4);387388reg = INT_HPD;389writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA);390}391392void analogix_dp_init_hpd(struct analogix_dp_device *dp)393{394u32 reg;395396if (dp->hpd_gpiod)397return;398399analogix_dp_clear_hotplug_interrupts(dp);400401reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_3);402reg &= ~(F_HPD | HPD_CTRL);403writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_3);404}405406void analogix_dp_force_hpd(struct analogix_dp_device *dp)407{408u32 reg;409410reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_3);411reg = (F_HPD | HPD_CTRL);412writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_3);413}414415enum dp_irq_type analogix_dp_get_irq_type(struct analogix_dp_device *dp)416{417u32 reg;418419if (dp->hpd_gpiod) {420reg = gpiod_get_value(dp->hpd_gpiod);421if (reg)422return DP_IRQ_TYPE_HP_CABLE_IN;423else424return DP_IRQ_TYPE_HP_CABLE_OUT;425} else {426/* Parse hotplug interrupt status register */427reg = readl(dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_4);428429if (reg & PLUG)430return DP_IRQ_TYPE_HP_CABLE_IN;431432if (reg & HPD_LOST)433return DP_IRQ_TYPE_HP_CABLE_OUT;434435if (reg & HOTPLUG_CHG)436return DP_IRQ_TYPE_HP_CHANGE;437438return DP_IRQ_TYPE_UNKNOWN;439}440}441442void analogix_dp_reset_aux(struct analogix_dp_device *dp)443{444u32 reg;445446/* Disable AUX channel module */447reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_2);448reg |= AUX_FUNC_EN_N;449writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_2);450}451452void analogix_dp_init_aux(struct analogix_dp_device *dp)453{454u32 reg;455456/* Clear inerrupts related to AUX channel */457reg = RPLY_RECEIV | AUX_ERR;458writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA);459460analogix_dp_set_analog_power_down(dp, AUX_BLOCK, true);461usleep_range(10, 11);462analogix_dp_set_analog_power_down(dp, AUX_BLOCK, false);463464analogix_dp_reset_aux(dp);465466/* AUX_BIT_PERIOD_EXPECTED_DELAY doesn't apply to Rockchip IP */467if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))468reg = 0;469else470reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3);471472/* Disable AUX transaction H/W retry */473reg |= AUX_HW_RETRY_COUNT_SEL(0) |474AUX_HW_RETRY_INTERVAL_600_MICROSECONDS;475476writel(reg, dp->reg_base + ANALOGIX_DP_AUX_HW_RETRY_CTL);477478/* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */479reg = DEFER_CTRL_EN | DEFER_COUNT(1);480writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_DEFER_CTL);481482/* Enable AUX channel module */483reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_2);484reg &= ~AUX_FUNC_EN_N;485writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_2);486}487488int analogix_dp_get_plug_in_status(struct analogix_dp_device *dp)489{490u32 reg;491492if (dp->hpd_gpiod) {493if (gpiod_get_value(dp->hpd_gpiod))494return 0;495} else {496reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_3);497if (reg & HPD_STATUS)498return 0;499}500501return -EINVAL;502}503504void analogix_dp_enable_sw_function(struct analogix_dp_device *dp)505{506u32 reg;507508reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_1);509reg &= ~SW_FUNC_EN_N;510writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_1);511}512513void analogix_dp_set_link_bandwidth(struct analogix_dp_device *dp, u32 bwtype)514{515u32 reg;516int ret;517518reg = bwtype;519if ((bwtype == DP_LINK_BW_2_7) || (bwtype == DP_LINK_BW_1_62))520writel(reg, dp->reg_base + ANALOGIX_DP_LINK_BW_SET);521522if (dp->phy) {523union phy_configure_opts phy_cfg = {0};524525phy_cfg.dp.link_rate =526drm_dp_bw_code_to_link_rate(dp->link_train.link_rate) / 100;527phy_cfg.dp.set_rate = true;528ret = phy_configure(dp->phy, &phy_cfg);529if (ret && ret != -EOPNOTSUPP) {530dev_err(dp->dev, "%s: phy_configure() failed: %d\n", __func__, ret);531return;532}533}534}535536void analogix_dp_get_link_bandwidth(struct analogix_dp_device *dp, u32 *bwtype)537{538u32 reg;539540reg = readl(dp->reg_base + ANALOGIX_DP_LINK_BW_SET);541*bwtype = reg;542}543544void analogix_dp_set_lane_count(struct analogix_dp_device *dp, u32 count)545{546u32 reg;547int ret;548549reg = count;550writel(reg, dp->reg_base + ANALOGIX_DP_LANE_COUNT_SET);551552if (dp->phy) {553union phy_configure_opts phy_cfg = {0};554555phy_cfg.dp.lanes = dp->link_train.lane_count;556phy_cfg.dp.set_lanes = true;557ret = phy_configure(dp->phy, &phy_cfg);558if (ret && ret != -EOPNOTSUPP) {559dev_err(dp->dev, "%s: phy_configure() failed: %d\n", __func__, ret);560return;561}562}563}564565void analogix_dp_get_lane_count(struct analogix_dp_device *dp, u32 *count)566{567u32 reg;568569reg = readl(dp->reg_base + ANALOGIX_DP_LANE_COUNT_SET);570*count = reg;571}572573void analogix_dp_set_lane_link_training(struct analogix_dp_device *dp)574{575u8 lane;576int ret;577578for (lane = 0; lane < dp->link_train.lane_count; lane++)579writel(dp->link_train.training_lane[lane],580dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL + 4 * lane);581582if (dp->phy) {583union phy_configure_opts phy_cfg = {0};584585for (lane = 0; lane < dp->link_train.lane_count; lane++) {586u8 training_lane = dp->link_train.training_lane[lane];587u8 vs, pe;588589vs = (training_lane & DP_TRAIN_VOLTAGE_SWING_MASK) >>590DP_TRAIN_VOLTAGE_SWING_SHIFT;591pe = (training_lane & DP_TRAIN_PRE_EMPHASIS_MASK) >>592DP_TRAIN_PRE_EMPHASIS_SHIFT;593phy_cfg.dp.voltage[lane] = vs;594phy_cfg.dp.pre[lane] = pe;595}596597phy_cfg.dp.set_voltages = true;598ret = phy_configure(dp->phy, &phy_cfg);599if (ret && ret != -EOPNOTSUPP) {600dev_err(dp->dev, "%s: phy_configure() failed: %d\n", __func__, ret);601return;602}603}604}605606u32 analogix_dp_get_lane_link_training(struct analogix_dp_device *dp, u8 lane)607{608return readl(dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL + 4 * lane);609}610611void analogix_dp_enable_enhanced_mode(struct analogix_dp_device *dp,612bool enable)613{614u32 reg;615616if (enable) {617reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_4);618reg |= ENHANCED;619writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_4);620} else {621reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_4);622reg &= ~ENHANCED;623writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_4);624}625}626627void analogix_dp_set_training_pattern(struct analogix_dp_device *dp,628enum pattern_set pattern)629{630u32 reg;631632switch (pattern) {633case PRBS7:634reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7;635writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET);636break;637case D10_2:638reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2;639writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET);640break;641case TRAINING_PTN1:642reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1;643writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET);644break;645case TRAINING_PTN2:646reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2;647writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET);648break;649case DP_NONE:650reg = SCRAMBLING_ENABLE |651LINK_QUAL_PATTERN_SET_DISABLE |652SW_TRAINING_PATTERN_SET_NORMAL;653writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET);654break;655default:656break;657}658}659660void analogix_dp_reset_macro(struct analogix_dp_device *dp)661{662u32 reg;663664reg = readl(dp->reg_base + ANALOGIX_DP_PHY_TEST);665reg |= MACRO_RST;666writel(reg, dp->reg_base + ANALOGIX_DP_PHY_TEST);667668/* 10 us is the minimum reset time. */669usleep_range(10, 20);670671reg &= ~MACRO_RST;672writel(reg, dp->reg_base + ANALOGIX_DP_PHY_TEST);673}674675void analogix_dp_init_video(struct analogix_dp_device *dp)676{677u32 reg;678679reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG;680writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_1);681682reg = 0x0;683writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_1);684685reg = CHA_CRI(4) | CHA_CTRL;686writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_2);687688reg = 0x0;689writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_3);690691reg = VID_HRES_TH(2) | VID_VRES_TH(0);692writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_8);693}694695void analogix_dp_set_video_color_format(struct analogix_dp_device *dp)696{697u32 reg;698699/* Configure the input color depth, color space, dynamic range */700reg = (dp->video_info.dynamic_range << IN_D_RANGE_SHIFT) |701(dp->video_info.color_depth << IN_BPC_SHIFT) |702(dp->video_info.color_space << IN_COLOR_F_SHIFT);703writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_2);704705/* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */706reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_3);707reg &= ~IN_YC_COEFFI_MASK;708if (dp->video_info.ycbcr_coeff)709reg |= IN_YC_COEFFI_ITU709;710else711reg |= IN_YC_COEFFI_ITU601;712writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_3);713}714715int analogix_dp_is_slave_video_stream_clock_on(struct analogix_dp_device *dp)716{717u32 reg;718719reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_1);720writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_1);721722reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_1);723724if (!(reg & DET_STA)) {725dev_dbg(dp->dev, "Input stream clock not detected.\n");726return -EINVAL;727}728729reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_2);730writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_2);731732reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_2);733dev_dbg(dp->dev, "wait SYS_CTL_2.\n");734735if (reg & CHA_STA) {736dev_dbg(dp->dev, "Input stream clk is changing\n");737return -EINVAL;738}739740return 0;741}742743void analogix_dp_set_video_cr_mn(struct analogix_dp_device *dp,744enum clock_recovery_m_value_type type,745u32 m_value, u32 n_value)746{747u32 reg;748749if (type == REGISTER_M) {750reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_4);751reg |= FIX_M_VID;752writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_4);753reg = m_value & 0xff;754writel(reg, dp->reg_base + ANALOGIX_DP_M_VID_0);755reg = (m_value >> 8) & 0xff;756writel(reg, dp->reg_base + ANALOGIX_DP_M_VID_1);757reg = (m_value >> 16) & 0xff;758writel(reg, dp->reg_base + ANALOGIX_DP_M_VID_2);759760reg = n_value & 0xff;761writel(reg, dp->reg_base + ANALOGIX_DP_N_VID_0);762reg = (n_value >> 8) & 0xff;763writel(reg, dp->reg_base + ANALOGIX_DP_N_VID_1);764reg = (n_value >> 16) & 0xff;765writel(reg, dp->reg_base + ANALOGIX_DP_N_VID_2);766} else {767reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_4);768reg &= ~FIX_M_VID;769writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_4);770771writel(0x00, dp->reg_base + ANALOGIX_DP_N_VID_0);772writel(0x80, dp->reg_base + ANALOGIX_DP_N_VID_1);773writel(0x00, dp->reg_base + ANALOGIX_DP_N_VID_2);774}775}776777void analogix_dp_set_video_timing_mode(struct analogix_dp_device *dp, u32 type)778{779u32 reg;780781if (type == VIDEO_TIMING_FROM_CAPTURE) {782reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10);783reg &= ~FORMAT_SEL;784writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10);785} else {786reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10);787reg |= FORMAT_SEL;788writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10);789}790}791792void analogix_dp_enable_video_master(struct analogix_dp_device *dp, bool enable)793{794u32 reg;795796if (enable) {797reg = readl(dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL);798reg &= ~VIDEO_MODE_MASK;799reg |= VIDEO_MASTER_MODE_EN | VIDEO_MODE_MASTER_MODE;800writel(reg, dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL);801} else {802reg = readl(dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL);803reg &= ~VIDEO_MODE_MASK;804reg |= VIDEO_MODE_SLAVE_MODE;805writel(reg, dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL);806}807}808809void analogix_dp_start_video(struct analogix_dp_device *dp)810{811u32 reg;812813reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1);814reg |= VIDEO_EN;815writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1);816}817818int analogix_dp_is_video_stream_on(struct analogix_dp_device *dp)819{820u32 reg;821822reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_3);823writel(reg, dp->reg_base + ANALOGIX_DP_SYS_CTL_3);824825reg = readl(dp->reg_base + ANALOGIX_DP_SYS_CTL_3);826if (!(reg & STRM_VALID)) {827dev_dbg(dp->dev, "Input video stream is not detected.\n");828return -EINVAL;829}830831return 0;832}833834void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp)835{836u32 reg;837838reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_1);839if (dp->plat_data && is_rockchip(dp->plat_data->dev_type)) {840reg &= ~(RK_VID_CAP_FUNC_EN_N | RK_VID_FIFO_FUNC_EN_N);841} else {842reg &= ~(MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N);843reg |= MASTER_VID_FUNC_EN_N;844}845writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_1);846847reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10);848reg &= ~INTERACE_SCAN_CFG;849reg |= (dp->video_info.interlaced << 2);850writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10);851852reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10);853reg &= ~VSYNC_POLARITY_CFG;854reg |= (dp->video_info.v_sync_polarity << 1);855writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10);856857reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10);858reg &= ~HSYNC_POLARITY_CFG;859reg |= (dp->video_info.h_sync_polarity << 0);860writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10);861862reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE;863writel(reg, dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL);864}865866void analogix_dp_enable_scrambling(struct analogix_dp_device *dp)867{868u32 reg;869870reg = readl(dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET);871reg &= ~SCRAMBLING_DISABLE;872writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET);873}874875void analogix_dp_disable_scrambling(struct analogix_dp_device *dp)876{877u32 reg;878879reg = readl(dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET);880reg |= SCRAMBLING_DISABLE;881writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET);882}883884void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp)885{886writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON);887}888889static ssize_t analogix_dp_get_psr_status(struct analogix_dp_device *dp)890{891ssize_t val;892u8 status;893894val = drm_dp_dpcd_readb(&dp->aux, DP_PSR_STATUS, &status);895if (val < 0) {896dev_err(dp->dev, "PSR_STATUS read failed ret=%zd", val);897return val;898}899return status;900}901902int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,903struct dp_sdp *vsc, bool blocking)904{905unsigned int val;906int ret;907ssize_t psr_status;908909/* don't send info frame */910val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);911val &= ~IF_EN;912writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);913914/* configure single frame update mode */915writel(PSR_FRAME_UP_TYPE_BURST | PSR_CRC_SEL_HARDWARE,916dp->reg_base + ANALOGIX_DP_PSR_FRAME_UPDATE_CTRL);917918/* configure VSC HB0~HB3 */919writel(vsc->sdp_header.HB0, dp->reg_base + ANALOGIX_DP_SPD_HB0);920writel(vsc->sdp_header.HB1, dp->reg_base + ANALOGIX_DP_SPD_HB1);921writel(vsc->sdp_header.HB2, dp->reg_base + ANALOGIX_DP_SPD_HB2);922writel(vsc->sdp_header.HB3, dp->reg_base + ANALOGIX_DP_SPD_HB3);923924/* configure reused VSC PB0~PB3, magic number from vendor */925writel(0x00, dp->reg_base + ANALOGIX_DP_SPD_PB0);926writel(0x16, dp->reg_base + ANALOGIX_DP_SPD_PB1);927writel(0xCE, dp->reg_base + ANALOGIX_DP_SPD_PB2);928writel(0x5D, dp->reg_base + ANALOGIX_DP_SPD_PB3);929930/* configure DB0 / DB1 values */931writel(vsc->db[0], dp->reg_base + ANALOGIX_DP_VSC_SHADOW_DB0);932writel(vsc->db[1], dp->reg_base + ANALOGIX_DP_VSC_SHADOW_DB1);933934/* set reuse spd inforframe */935val = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_3);936val |= REUSE_SPD_EN;937writel(val, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_3);938939/* mark info frame update */940val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);941val = (val | IF_UP) & ~IF_EN;942writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);943944/* send info frame */945val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);946val |= IF_EN;947writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);948949if (!blocking)950return 0;951952/*953* db[1]!=0: entering PSR, wait for fully active remote frame buffer.954* db[1]==0: exiting PSR, wait for either955* (a) ACTIVE_RESYNC - the sink "must display the956* incoming active frames from the Source device with no visible957* glitches and/or artifacts", even though timings may still be958* re-synchronizing; or959* (b) INACTIVE - the transition is fully complete.960*/961ret = readx_poll_timeout(analogix_dp_get_psr_status, dp, psr_status,962psr_status >= 0 &&963((vsc->db[1] && psr_status == DP_PSR_SINK_ACTIVE_RFB) ||964(!vsc->db[1] && (psr_status == DP_PSR_SINK_ACTIVE_RESYNC ||965psr_status == DP_PSR_SINK_INACTIVE))),9661500, DP_TIMEOUT_PSR_LOOP_MS * 1000);967if (ret) {968dev_warn(dp->dev, "Failed to apply PSR %d\n", ret);969return ret;970}971return 0;972}973974ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,975struct drm_dp_aux_msg *msg)976{977u32 reg;978u8 *buffer = msg->buffer;979unsigned int i;980int ret;981982/* Buffer size of AUX CH is 16 bytes */983if (WARN_ON(msg->size > 16))984return -E2BIG;985986/* Clear AUX CH data buffer */987reg = BUF_CLR;988writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL);989990switch (msg->request & ~DP_AUX_I2C_MOT) {991case DP_AUX_I2C_WRITE:992reg = AUX_TX_COMM_WRITE | AUX_TX_COMM_I2C_TRANSACTION;993if (msg->request & DP_AUX_I2C_MOT)994reg |= AUX_TX_COMM_MOT;995break;996997case DP_AUX_I2C_READ:998reg = AUX_TX_COMM_READ | AUX_TX_COMM_I2C_TRANSACTION;999if (msg->request & DP_AUX_I2C_MOT)1000reg |= AUX_TX_COMM_MOT;1001break;10021003case DP_AUX_NATIVE_WRITE:1004reg = AUX_TX_COMM_WRITE | AUX_TX_COMM_DP_TRANSACTION;1005break;10061007case DP_AUX_NATIVE_READ:1008reg = AUX_TX_COMM_READ | AUX_TX_COMM_DP_TRANSACTION;1009break;10101011default:1012return -EINVAL;1013}10141015reg |= AUX_LENGTH(msg->size);1016writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1);10171018/* Select DPCD device address */1019reg = AUX_ADDR_7_0(msg->address);1020writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0);1021reg = AUX_ADDR_15_8(msg->address);1022writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8);1023reg = AUX_ADDR_19_16(msg->address);1024writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16);10251026if (!(msg->request & DP_AUX_I2C_READ)) {1027for (i = 0; i < msg->size; i++) {1028reg = buffer[i];1029writel(reg, dp->reg_base + ANALOGIX_DP_BUF_DATA_0 +10304 * i);1031}1032}10331034/* Enable AUX CH operation */1035reg = AUX_EN;10361037/* Zero-sized messages specify address-only transactions. */1038if (msg->size < 1)1039reg |= ADDR_ONLY;10401041writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2);10421043ret = readx_poll_timeout(readl, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2,1044reg, !(reg & AUX_EN), 25, 500 * 1000);1045if (ret) {1046dev_err(dp->dev, "AUX CH enable timeout!\n");1047goto aux_error;1048}10491050/* TODO: Wait for an interrupt instead of looping? */1051/* Is AUX CH command reply received? */1052ret = readx_poll_timeout(readl, dp->reg_base + ANALOGIX_DP_INT_STA,1053reg, reg & RPLY_RECEIV, 10, 20 * 1000);1054if (ret) {1055dev_err(dp->dev, "AUX CH cmd reply timeout!\n");1056goto aux_error;1057}10581059/* Clear interrupt source for AUX CH command reply */1060writel(RPLY_RECEIV, dp->reg_base + ANALOGIX_DP_INT_STA);10611062/* Clear interrupt source for AUX CH access error */1063reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA);1064if ((reg & AUX_ERR)) {1065u32 aux_status = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_STA) &1066AUX_STATUS_MASK;10671068writel(AUX_ERR, dp->reg_base + ANALOGIX_DP_INT_STA);10691070if (aux_status == AUX_STATUS_TIMEOUT_ERROR)1071return -ETIMEDOUT;10721073dev_warn(dp->dev, "AUX CH error happened: %#x (%d)\n",1074aux_status, !!(reg & AUX_ERR));1075goto aux_error;1076}10771078if (msg->request & DP_AUX_I2C_READ) {1079for (i = 0; i < msg->size; i++) {1080reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0 +10814 * i);1082buffer[i] = (unsigned char)reg;1083}1084}10851086/* Check if Rx sends defer */1087reg = readl(dp->reg_base + ANALOGIX_DP_AUX_RX_COMM);1088if (reg == AUX_RX_COMM_AUX_DEFER)1089msg->reply = DP_AUX_NATIVE_REPLY_DEFER;1090else if (reg == AUX_RX_COMM_I2C_DEFER)1091msg->reply = DP_AUX_I2C_REPLY_DEFER;1092else if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_WRITE ||1093(msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_READ)1094msg->reply = DP_AUX_I2C_REPLY_ACK;1095else if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_WRITE ||1096(msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_READ)1097msg->reply = DP_AUX_NATIVE_REPLY_ACK;10981099return msg->size;11001101aux_error:1102/* if aux err happen, reset aux */1103analogix_dp_init_aux(dp);11041105return -EREMOTEIO;1106}110711081109