330 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			330 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0
 | |
| /*
 | |
|  * Copyright (C) 2023 Rockchip Electronics Co., Ltd.
 | |
|  *
 | |
|  * Author: Zhang Yubing <yubing.zhang@rock-chips.com>
 | |
|  */
 | |
| 
 | |
| #include "hal/cru_api.h"
 | |
| #include "rkx110_x120.h"
 | |
| #include "rkx110_x120_display.h"
 | |
| #include "rkx110_dsi_rx.h"
 | |
| #include "rkx120_dsi_tx.h"
 | |
| 
 | |
| int rk_serdes_display_route_prepare(struct rk_serdes *serdes, struct rk_serdes_route *route)
 | |
| {
 | |
| 	u32 local_port;
 | |
| 
 | |
| 	local_port = route->local_port0 ? route->local_port0 : route->local_port1;
 | |
| 
 | |
| 	switch (local_port) {
 | |
| 	case RK_SERDES_RGB_RX:
 | |
| 		rkx110_rgb_rx_enable(serdes, route);
 | |
| 		break;
 | |
| 	case RK_SERDES_LVDS_RX0:
 | |
| 		rkx110_lvds_rx_enable(serdes, route, 0);
 | |
| 		break;
 | |
| 	case RK_SERDES_LVDS_RX1:
 | |
| 		rkx110_lvds_rx_enable(serdes, route, 1);
 | |
| 		break;
 | |
| 	case RK_SERDES_DUAL_LVDS_RX:
 | |
| 		rkx110_lvds_rx_enable(serdes, route, 0);
 | |
| 		rkx110_lvds_rx_enable(serdes, route, 1);
 | |
| 		break;
 | |
| 	case RK_SERDES_DSI_RX0:
 | |
| 		rkx110_dsi_rx_enable(serdes, route, 0);
 | |
| 		break;
 | |
| 	case RK_SERDES_DSI_RX1:
 | |
| 		rkx110_dsi_rx_enable(serdes, route, 1);
 | |
| 		break;
 | |
| 	default:
 | |
| 		dev_info(serdes->dev, "undefined local port\n");
 | |
| 	}
 | |
| 
 | |
| 	rkx110_display_linktx_enable(serdes, route);
 | |
| 
 | |
| 	if (route->local_port0) {
 | |
| 		rkx120_display_linkrx_enable(serdes, route, DEVICE_REMOTE0);
 | |
| 		if (serdes->remote_nr == 2 && serdes->route_nr != 2)
 | |
| 			rkx120_display_linkrx_enable(serdes, route, DEVICE_REMOTE1);
 | |
| 
 | |
| 		if (route->remote0_port0 & RK_SERDES_DSI_TX0)
 | |
| 			rkx120_dsi_tx_pre_enable(serdes, route, DEVICE_REMOTE0);
 | |
| 		if (route->remote1_port0 & RK_SERDES_DSI_TX0)
 | |
| 			rkx120_dsi_tx_pre_enable(serdes, route, DEVICE_REMOTE1);
 | |
| 	}
 | |
| 
 | |
| 	if (route->local_port1) {
 | |
| 		if (serdes->remote_nr == 2)
 | |
| 			rkx120_display_linkrx_enable(serdes, route, DEVICE_REMOTE1);
 | |
| 		else
 | |
| 			rkx120_display_linkrx_enable(serdes, route, DEVICE_REMOTE0);
 | |
| 
 | |
| 		if (route->remote1_port0 & RK_SERDES_DSI_TX0)
 | |
| 			rkx120_dsi_tx_pre_enable(serdes, route, DEVICE_REMOTE1);
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int rk_serdes_display_video_start(struct rk_serdes *serdes,
 | |
| 					 struct rk_serdes_route *route, bool enable)
 | |
| {
 | |
| 	if (route->local_port0) {
 | |
| 		if (route->route_flag & ROUTE_MULTI_CHANNEL) {
 | |
| 			if (route->route_flag & ROUTE_MULTI_REMOTE) {
 | |
| 				rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE0, enable);
 | |
| 				rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE1, enable);
 | |
| 			} else {
 | |
| 				rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE0, enable);
 | |
| 				rkx120_linkrx_engine_enable(serdes, 1, DEVICE_REMOTE0, enable);
 | |
| 			}
 | |
| 			rkx110_linktx_channel_enable(serdes, 0, DEVICE_LOCAL, enable);
 | |
| 			rkx110_linktx_channel_enable(serdes, 1, DEVICE_LOCAL, enable);
 | |
| 		} else {
 | |
| 			rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE0, enable);
 | |
| 			rkx110_linktx_channel_enable(serdes, 0, DEVICE_LOCAL, enable);
 | |
| 		}
 | |
| 	} else {
 | |
| 		if (serdes->remote_nr == 2)
 | |
| 			rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE1, enable);
 | |
| 		else
 | |
| 			rkx120_linkrx_engine_enable(serdes, 1, DEVICE_REMOTE0, enable);
 | |
| 
 | |
| 		rkx110_linktx_channel_enable(serdes, 1, DEVICE_LOCAL, enable);
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int rk_serdes_display_route_init(struct  rk_serdes *serdes)
 | |
| {
 | |
| 	rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE0, false);
 | |
| 	if (serdes->remote_nr == 2)
 | |
| 		rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE1, false);
 | |
| 	else
 | |
| 		rkx120_linkrx_engine_enable(serdes, 1, DEVICE_REMOTE0, false);
 | |
| 
 | |
| 	rkx110_linktx_channel_enable(serdes, 0, DEVICE_LOCAL, false);
 | |
| 	rkx110_linktx_channel_enable(serdes, 1, DEVICE_LOCAL, false);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int rk_serdes_display_route_enable(struct rk_serdes *serdes, struct rk_serdes_route *route)
 | |
| {
 | |
| 	if (route->remote0_port0) {
 | |
| 		switch (route->remote0_port0) {
 | |
| 		case RK_SERDES_RGB_TX:
 | |
| 			rkx120_rgb_tx_enable(serdes, route, DEVICE_REMOTE0);
 | |
| 			break;
 | |
| 		case RK_SERDES_LVDS_TX0:
 | |
| 			rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 0);
 | |
| 			break;
 | |
| 		case RK_SERDES_LVDS_TX1:
 | |
| 			rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 1);
 | |
| 			break;
 | |
| 		case RK_SERDES_DUAL_LVDS_TX:
 | |
| 			rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 0);
 | |
| 			rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 1);
 | |
| 			break;
 | |
| 		case RK_SERDES_DSI_TX0:
 | |
| 			rkx120_dsi_tx_enable(serdes, route, DEVICE_REMOTE0);
 | |
| 			break;
 | |
| 		default:
 | |
| 			dev_err(serdes->dev, "undefined remote0_port0\n");
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (route->remote1_port0) {
 | |
| 		switch (route->remote1_port0) {
 | |
| 		case RK_SERDES_RGB_TX:
 | |
| 			rkx120_rgb_tx_enable(serdes, route, DEVICE_REMOTE1);
 | |
| 			break;
 | |
| 		case RK_SERDES_LVDS_TX0:
 | |
| 			rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE1, 0);
 | |
| 			break;
 | |
| 		case RK_SERDES_LVDS_TX1:
 | |
| 			rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE1, 1);
 | |
| 			break;
 | |
| 		case RK_SERDES_DUAL_LVDS_TX:
 | |
| 			rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE1, 0);
 | |
| 			rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE1, 1);
 | |
| 			break;
 | |
| 		case RK_SERDES_DSI_TX0:
 | |
| 			rkx120_dsi_tx_enable(serdes, route, DEVICE_REMOTE1);
 | |
| 			break;
 | |
| 		default:
 | |
| 			dev_err(serdes->dev, "undefined remote1_port0\n");
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (route->remote0_port1) {
 | |
| 		switch (route->remote0_port1) {
 | |
| 		case RK_SERDES_LVDS_TX0:
 | |
| 			rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 0);
 | |
| 			break;
 | |
| 		case RK_SERDES_LVDS_TX1:
 | |
| 			rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 1);
 | |
| 			break;
 | |
| 		default:
 | |
| 			dev_err(serdes->dev, "undefined remote0_port1\n");
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (serdes->version == SERDES_V1)
 | |
| 		rk_serdes_display_video_start(serdes, route, true);
 | |
| 
 | |
| 	rkx110_linktx_video_enable(serdes, DEVICE_LOCAL, true);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int rk_serdes_display_route_disable(struct rk_serdes *serdes, struct rk_serdes_route *route)
 | |
| {
 | |
| 	if (route->remote0_port0) {
 | |
| 		switch (route->remote0_port0) {
 | |
| 		case RK_SERDES_RGB_TX:
 | |
| 			break;
 | |
| 		case RK_SERDES_LVDS_TX0:
 | |
| 			rkx120_lvds_tx_disable(serdes, route, DEVICE_REMOTE0, 0);
 | |
| 			break;
 | |
| 		case RK_SERDES_LVDS_TX1:
 | |
| 			rkx120_lvds_tx_disable(serdes, route, DEVICE_REMOTE0, 1);
 | |
| 			break;
 | |
| 		case RK_SERDES_DUAL_LVDS_TX:
 | |
| 			rkx120_lvds_tx_disable(serdes, route, DEVICE_REMOTE0, 0);
 | |
| 			rkx120_lvds_tx_disable(serdes, route, DEVICE_REMOTE0, 1);
 | |
| 			break;
 | |
| 		case RK_SERDES_DSI_TX0:
 | |
| 			rkx120_dsi_tx_disable(serdes, route, DEVICE_REMOTE0);
 | |
| 			break;
 | |
| 		default:
 | |
| 			dev_err(serdes->dev, "undefined remote0_port0\n");
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (route->remote1_port0) {
 | |
| 		switch (route->remote1_port0) {
 | |
| 		case RK_SERDES_RGB_TX:
 | |
| 			break;
 | |
| 		case RK_SERDES_LVDS_TX0:
 | |
| 			rkx120_lvds_tx_disable(serdes, route, DEVICE_REMOTE1, 0);
 | |
| 			break;
 | |
| 		case RK_SERDES_LVDS_TX1:
 | |
| 			rkx120_lvds_tx_disable(serdes, route, DEVICE_REMOTE1, 1);
 | |
| 			break;
 | |
| 		case RK_SERDES_DUAL_LVDS_TX:
 | |
| 			rkx120_lvds_tx_disable(serdes, route, DEVICE_REMOTE1, 0);
 | |
| 			rkx120_lvds_tx_disable(serdes, route, DEVICE_REMOTE1, 1);
 | |
| 			break;
 | |
| 		case RK_SERDES_DSI_TX0:
 | |
| 			rkx120_dsi_tx_disable(serdes, route, DEVICE_REMOTE1);
 | |
| 			break;
 | |
| 		default:
 | |
| 			dev_err(serdes->dev, "undefined remote1_port0\n");
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (route->remote0_port1) {
 | |
| 		switch (route->remote0_port1) {
 | |
| 		case RK_SERDES_LVDS_TX0:
 | |
| 			rkx120_lvds_tx_disable(serdes, route, DEVICE_REMOTE0, 0);
 | |
| 			break;
 | |
| 		case RK_SERDES_LVDS_TX1:
 | |
| 			rkx120_lvds_tx_disable(serdes, route, DEVICE_REMOTE0, 1);
 | |
| 			break;
 | |
| 		default:
 | |
| 			dev_err(serdes->dev, "undefined remote0_port1\n");
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (serdes->version == SERDES_V1) {
 | |
| 		rk_serdes_display_video_start(serdes, route, false);
 | |
| 
 | |
| 		if (route->local_port0 == RK_SERDES_DUAL_LVDS_RX) {
 | |
| 			rkx110_set_stream_source(serdes, RK_SERDES_RGB_RX,
 | |
| 						 DEVICE_LOCAL);
 | |
| 			hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
 | |
| 				    RKX110_SRST_RESETN_2X_LVDS_RKLINK_TX);
 | |
| 			hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
 | |
| 				    RKX110_SRST_RESETN_D_LVDS0_RKLINK_TX);
 | |
| 			hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
 | |
| 				    RKX110_SRST_RESETN_D_LVDS1_RKLINK_TX);
 | |
| 		}
 | |
| 
 | |
| 		if ((route->local_port0 == RK_SERDES_DSI_RX0) ||
 | |
| 		    (route->local_port1 == RK_SERDES_DSI_RX0)) {
 | |
| 			serdes->i2c_write_reg(serdes->chip[DEVICE_LOCAL].client, 0x0314,
 | |
| 					      0x1400140);
 | |
| 			hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
 | |
| 				    RKX111_SRST_RESETN_D_DSI_0_REC_RKLINK_TX);
 | |
| 			hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
 | |
| 				    RKX110_SRST_RESETN_D_DSI_0_RKLINK_TX);
 | |
| 		}
 | |
| 
 | |
| 		if ((route->local_port0 == RK_SERDES_DSI_RX1) ||
 | |
| 		    (route->local_port1 == RK_SERDES_DSI_RX1)) {
 | |
| 			serdes->i2c_write_reg(serdes->chip[DEVICE_LOCAL].client, 0x0314,
 | |
| 					      0x2800280);
 | |
| 			hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
 | |
| 				    RKX111_SRST_RESETN_D_DSI_1_REC_RKLINK_TX);
 | |
| 			hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
 | |
| 				    RKX110_SRST_RESETN_D_DSI_1_RKLINK_TX);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int rk_serdes_display_route_unprepare(struct rk_serdes *serdes, struct rk_serdes_route *route)
 | |
| {
 | |
| 	if (route->remote0_port0 & RK_SERDES_DSI_TX0)
 | |
| 		rkx120_dsi_tx_post_disable(serdes, route, DEVICE_REMOTE0);
 | |
| 
 | |
| 	if (route->remote1_port0 & RK_SERDES_DSI_TX0)
 | |
| 		rkx120_dsi_tx_post_disable(serdes, route, DEVICE_REMOTE1);
 | |
| 
 | |
| 	if (serdes->version == SERDES_V1) {
 | |
| 		if (route->local_port0 == RK_SERDES_DUAL_LVDS_RX) {
 | |
| 			hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
 | |
| 					     RKX110_SRST_RESETN_2X_LVDS_RKLINK_TX);
 | |
| 			hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
 | |
| 					     RKX110_SRST_RESETN_D_LVDS0_RKLINK_TX);
 | |
| 			hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
 | |
| 					     RKX110_SRST_RESETN_D_LVDS1_RKLINK_TX);
 | |
| 			rkx110_set_stream_source(serdes, RK_SERDES_DUAL_LVDS_RX,
 | |
| 						    DEVICE_LOCAL);
 | |
| 		}
 | |
| 
 | |
| 		if ((route->local_port0 == RK_SERDES_DSI_RX0) ||
 | |
| 		    (route->local_port1 == RK_SERDES_DSI_RX0)) {
 | |
| 			hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
 | |
| 					     RKX110_SRST_RESETN_D_DSI_0_RKLINK_TX);
 | |
| 			hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
 | |
| 					     RKX111_SRST_RESETN_D_DSI_0_REC_RKLINK_TX);
 | |
| 			serdes->i2c_write_reg(serdes->chip[DEVICE_LOCAL].client, 0x0314,
 | |
| 					      0x1400000);
 | |
| 		}
 | |
| 
 | |
| 		if ((route->local_port0 == RK_SERDES_DSI_RX1) ||
 | |
| 		    (route->local_port1 == RK_SERDES_DSI_RX1)) {
 | |
| 			hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
 | |
| 					     RKX110_SRST_RESETN_D_DSI_1_RKLINK_TX);
 | |
| 			hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
 | |
| 					     RKX111_SRST_RESETN_D_DSI_1_REC_RKLINK_TX);
 | |
| 			serdes->i2c_write_reg(serdes->chip[DEVICE_LOCAL].client, 0x0314,
 | |
| 					      0x2800000);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 |