brintos

brintos / linux-shallow public Read only

0
0
Text · 24.9 KiB · 9a259c7 Raw
1063 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Thunderbolt Time Management Unit (TMU) support4 *5 * Copyright (C) 2019, Intel Corporation6 * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>7 *	    Rajmohan Mani <rajmohan.mani@intel.com>8 */9 10#include <linux/delay.h>11 12#include "tb.h"13 14static const unsigned int tmu_rates[] = {15	[TB_SWITCH_TMU_MODE_OFF] = 0,16	[TB_SWITCH_TMU_MODE_LOWRES] = 1000,17	[TB_SWITCH_TMU_MODE_HIFI_UNI] = 16,18	[TB_SWITCH_TMU_MODE_HIFI_BI] = 16,19	[TB_SWITCH_TMU_MODE_MEDRES_ENHANCED_UNI] = 16,20};21 22static const struct {23	unsigned int freq_meas_window;24	unsigned int avg_const;25	unsigned int delta_avg_const;26	unsigned int repl_timeout;27	unsigned int repl_threshold;28	unsigned int repl_n;29	unsigned int dirswitch_n;30} tmu_params[] = {31	[TB_SWITCH_TMU_MODE_OFF] = { },32	[TB_SWITCH_TMU_MODE_LOWRES] = { 30, 4, },33	[TB_SWITCH_TMU_MODE_HIFI_UNI] = { 800, 8, },34	[TB_SWITCH_TMU_MODE_HIFI_BI] = { 800, 8, },35	[TB_SWITCH_TMU_MODE_MEDRES_ENHANCED_UNI] = {36		800, 4, 0, 3125, 25, 128, 255,37	},38};39 40static const char *tmu_mode_name(enum tb_switch_tmu_mode mode)41{42	switch (mode) {43	case TB_SWITCH_TMU_MODE_OFF:44		return "off";45	case TB_SWITCH_TMU_MODE_LOWRES:46		return "uni-directional, LowRes";47	case TB_SWITCH_TMU_MODE_HIFI_UNI:48		return "uni-directional, HiFi";49	case TB_SWITCH_TMU_MODE_HIFI_BI:50		return "bi-directional, HiFi";51	case TB_SWITCH_TMU_MODE_MEDRES_ENHANCED_UNI:52		return "enhanced uni-directional, MedRes";53	default:54		return "unknown";55	}56}57 58static bool tb_switch_tmu_enhanced_is_supported(const struct tb_switch *sw)59{60	return usb4_switch_version(sw) > 1;61}62 63static int tb_switch_set_tmu_mode_params(struct tb_switch *sw,64					 enum tb_switch_tmu_mode mode)65{66	u32 freq, avg, val;67	int ret;68 69	freq = tmu_params[mode].freq_meas_window;70	avg = tmu_params[mode].avg_const;71 72	ret = tb_sw_read(sw, &val, TB_CFG_SWITCH,73			 sw->tmu.cap + TMU_RTR_CS_0, 1);74	if (ret)75		return ret;76 77	val &= ~TMU_RTR_CS_0_FREQ_WIND_MASK;78	val |= FIELD_PREP(TMU_RTR_CS_0_FREQ_WIND_MASK, freq);79 80	ret = tb_sw_write(sw, &val, TB_CFG_SWITCH,81			  sw->tmu.cap + TMU_RTR_CS_0, 1);82	if (ret)83		return ret;84 85	ret = tb_sw_read(sw, &val, TB_CFG_SWITCH,86			 sw->tmu.cap + TMU_RTR_CS_15, 1);87	if (ret)88		return ret;89 90	val &= ~TMU_RTR_CS_15_FREQ_AVG_MASK &91		~TMU_RTR_CS_15_DELAY_AVG_MASK &92		~TMU_RTR_CS_15_OFFSET_AVG_MASK &93		~TMU_RTR_CS_15_ERROR_AVG_MASK;94	val |=  FIELD_PREP(TMU_RTR_CS_15_FREQ_AVG_MASK, avg) |95		FIELD_PREP(TMU_RTR_CS_15_DELAY_AVG_MASK, avg) |96		FIELD_PREP(TMU_RTR_CS_15_OFFSET_AVG_MASK, avg) |97		FIELD_PREP(TMU_RTR_CS_15_ERROR_AVG_MASK, avg);98 99	ret = tb_sw_write(sw, &val, TB_CFG_SWITCH,100			 sw->tmu.cap + TMU_RTR_CS_15, 1);101	if (ret)102		return ret;103 104	if (tb_switch_tmu_enhanced_is_supported(sw)) {105		u32 delta_avg = tmu_params[mode].delta_avg_const;106 107		ret = tb_sw_read(sw, &val, TB_CFG_SWITCH,108				 sw->tmu.cap + TMU_RTR_CS_18, 1);109		if (ret)110			return ret;111 112		val &= ~TMU_RTR_CS_18_DELTA_AVG_CONST_MASK;113		val |= FIELD_PREP(TMU_RTR_CS_18_DELTA_AVG_CONST_MASK, delta_avg);114 115		ret = tb_sw_write(sw, &val, TB_CFG_SWITCH,116				  sw->tmu.cap + TMU_RTR_CS_18, 1);117	}118 119	return ret;120}121 122static bool tb_switch_tmu_ucap_is_supported(struct tb_switch *sw)123{124	int ret;125	u32 val;126 127	ret = tb_sw_read(sw, &val, TB_CFG_SWITCH,128			 sw->tmu.cap + TMU_RTR_CS_0, 1);129	if (ret)130		return false;131 132	return !!(val & TMU_RTR_CS_0_UCAP);133}134 135static int tb_switch_tmu_rate_read(struct tb_switch *sw)136{137	int ret;138	u32 val;139 140	ret = tb_sw_read(sw, &val, TB_CFG_SWITCH,141			 sw->tmu.cap + TMU_RTR_CS_3, 1);142	if (ret)143		return ret;144 145	val >>= TMU_RTR_CS_3_TS_PACKET_INTERVAL_SHIFT;146	return val;147}148 149static int tb_switch_tmu_rate_write(struct tb_switch *sw, int rate)150{151	int ret;152	u32 val;153 154	ret = tb_sw_read(sw, &val, TB_CFG_SWITCH,155			 sw->tmu.cap + TMU_RTR_CS_3, 1);156	if (ret)157		return ret;158 159	val &= ~TMU_RTR_CS_3_TS_PACKET_INTERVAL_MASK;160	val |= rate << TMU_RTR_CS_3_TS_PACKET_INTERVAL_SHIFT;161 162	return tb_sw_write(sw, &val, TB_CFG_SWITCH,163			   sw->tmu.cap + TMU_RTR_CS_3, 1);164}165 166static int tb_port_tmu_write(struct tb_port *port, u8 offset, u32 mask,167			     u32 value)168{169	u32 data;170	int ret;171 172	ret = tb_port_read(port, &data, TB_CFG_PORT, port->cap_tmu + offset, 1);173	if (ret)174		return ret;175 176	data &= ~mask;177	data |= value;178 179	return tb_port_write(port, &data, TB_CFG_PORT,180			     port->cap_tmu + offset, 1);181}182 183static int tb_port_tmu_set_unidirectional(struct tb_port *port,184					  bool unidirectional)185{186	u32 val;187 188	if (!port->sw->tmu.has_ucap)189		return 0;190 191	val = unidirectional ? TMU_ADP_CS_3_UDM : 0;192	return tb_port_tmu_write(port, TMU_ADP_CS_3, TMU_ADP_CS_3_UDM, val);193}194 195static inline int tb_port_tmu_unidirectional_disable(struct tb_port *port)196{197	return tb_port_tmu_set_unidirectional(port, false);198}199 200static inline int tb_port_tmu_unidirectional_enable(struct tb_port *port)201{202	return tb_port_tmu_set_unidirectional(port, true);203}204 205static bool tb_port_tmu_is_unidirectional(struct tb_port *port)206{207	int ret;208	u32 val;209 210	ret = tb_port_read(port, &val, TB_CFG_PORT,211			   port->cap_tmu + TMU_ADP_CS_3, 1);212	if (ret)213		return false;214 215	return val & TMU_ADP_CS_3_UDM;216}217 218static bool tb_port_tmu_is_enhanced(struct tb_port *port)219{220	int ret;221	u32 val;222 223	ret = tb_port_read(port, &val, TB_CFG_PORT,224			   port->cap_tmu + TMU_ADP_CS_8, 1);225	if (ret)226		return false;227 228	return val & TMU_ADP_CS_8_EUDM;229}230 231/* Can be called to non-v2 lane adapters too */232static int tb_port_tmu_enhanced_enable(struct tb_port *port, bool enable)233{234	int ret;235	u32 val;236 237	if (!tb_switch_tmu_enhanced_is_supported(port->sw))238		return 0;239 240	ret = tb_port_read(port, &val, TB_CFG_PORT,241			   port->cap_tmu + TMU_ADP_CS_8, 1);242	if (ret)243		return ret;244 245	if (enable)246		val |= TMU_ADP_CS_8_EUDM;247	else248		val &= ~TMU_ADP_CS_8_EUDM;249 250	return tb_port_write(port, &val, TB_CFG_PORT,251			     port->cap_tmu + TMU_ADP_CS_8, 1);252}253 254static int tb_port_set_tmu_mode_params(struct tb_port *port,255				       enum tb_switch_tmu_mode mode)256{257	u32 repl_timeout, repl_threshold, repl_n, dirswitch_n, val;258	int ret;259 260	repl_timeout = tmu_params[mode].repl_timeout;261	repl_threshold = tmu_params[mode].repl_threshold;262	repl_n = tmu_params[mode].repl_n;263	dirswitch_n = tmu_params[mode].dirswitch_n;264 265	ret = tb_port_read(port, &val, TB_CFG_PORT,266			   port->cap_tmu + TMU_ADP_CS_8, 1);267	if (ret)268		return ret;269 270	val &= ~TMU_ADP_CS_8_REPL_TIMEOUT_MASK;271	val &= ~TMU_ADP_CS_8_REPL_THRESHOLD_MASK;272	val |= FIELD_PREP(TMU_ADP_CS_8_REPL_TIMEOUT_MASK, repl_timeout);273	val |= FIELD_PREP(TMU_ADP_CS_8_REPL_THRESHOLD_MASK, repl_threshold);274 275	ret = tb_port_write(port, &val, TB_CFG_PORT,276			    port->cap_tmu + TMU_ADP_CS_8, 1);277	if (ret)278		return ret;279 280	ret = tb_port_read(port, &val, TB_CFG_PORT,281			   port->cap_tmu + TMU_ADP_CS_9, 1);282	if (ret)283		return ret;284 285	val &= ~TMU_ADP_CS_9_REPL_N_MASK;286	val &= ~TMU_ADP_CS_9_DIRSWITCH_N_MASK;287	val |= FIELD_PREP(TMU_ADP_CS_9_REPL_N_MASK, repl_n);288	val |= FIELD_PREP(TMU_ADP_CS_9_DIRSWITCH_N_MASK, dirswitch_n);289 290	return tb_port_write(port, &val, TB_CFG_PORT,291			     port->cap_tmu + TMU_ADP_CS_9, 1);292}293 294/* Can be called to non-v2 lane adapters too */295static int tb_port_tmu_rate_write(struct tb_port *port, int rate)296{297	int ret;298	u32 val;299 300	if (!tb_switch_tmu_enhanced_is_supported(port->sw))301		return 0;302 303	ret = tb_port_read(port, &val, TB_CFG_PORT,304			   port->cap_tmu + TMU_ADP_CS_9, 1);305	if (ret)306		return ret;307 308	val &= ~TMU_ADP_CS_9_ADP_TS_INTERVAL_MASK;309	val |= FIELD_PREP(TMU_ADP_CS_9_ADP_TS_INTERVAL_MASK, rate);310 311	return tb_port_write(port, &val, TB_CFG_PORT,312			     port->cap_tmu + TMU_ADP_CS_9, 1);313}314 315static int tb_port_tmu_time_sync(struct tb_port *port, bool time_sync)316{317	u32 val = time_sync ? TMU_ADP_CS_6_DTS : 0;318 319	return tb_port_tmu_write(port, TMU_ADP_CS_6, TMU_ADP_CS_6_DTS, val);320}321 322static int tb_port_tmu_time_sync_disable(struct tb_port *port)323{324	return tb_port_tmu_time_sync(port, true);325}326 327static int tb_port_tmu_time_sync_enable(struct tb_port *port)328{329	return tb_port_tmu_time_sync(port, false);330}331 332static int tb_switch_tmu_set_time_disruption(struct tb_switch *sw, bool set)333{334	u32 val, offset, bit;335	int ret;336 337	if (tb_switch_is_usb4(sw)) {338		offset = sw->tmu.cap + TMU_RTR_CS_0;339		bit = TMU_RTR_CS_0_TD;340	} else {341		offset = sw->cap_vsec_tmu + TB_TIME_VSEC_3_CS_26;342		bit = TB_TIME_VSEC_3_CS_26_TD;343	}344 345	ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, offset, 1);346	if (ret)347		return ret;348 349	if (set)350		val |= bit;351	else352		val &= ~bit;353 354	return tb_sw_write(sw, &val, TB_CFG_SWITCH, offset, 1);355}356 357static int tmu_mode_init(struct tb_switch *sw)358{359	bool enhanced, ucap;360	int ret, rate;361 362	ucap = tb_switch_tmu_ucap_is_supported(sw);363	if (ucap)364		tb_sw_dbg(sw, "TMU: supports uni-directional mode\n");365	enhanced = tb_switch_tmu_enhanced_is_supported(sw);366	if (enhanced)367		tb_sw_dbg(sw, "TMU: supports enhanced uni-directional mode\n");368 369	ret = tb_switch_tmu_rate_read(sw);370	if (ret < 0)371		return ret;372	rate = ret;373 374	/* Off by default */375	sw->tmu.mode = TB_SWITCH_TMU_MODE_OFF;376 377	if (tb_route(sw)) {378		struct tb_port *up = tb_upstream_port(sw);379 380		if (enhanced && tb_port_tmu_is_enhanced(up)) {381			sw->tmu.mode = TB_SWITCH_TMU_MODE_MEDRES_ENHANCED_UNI;382		} else if (ucap && tb_port_tmu_is_unidirectional(up)) {383			if (tmu_rates[TB_SWITCH_TMU_MODE_LOWRES] == rate)384				sw->tmu.mode = TB_SWITCH_TMU_MODE_LOWRES;385			else if (tmu_rates[TB_SWITCH_TMU_MODE_HIFI_UNI] == rate)386				sw->tmu.mode = TB_SWITCH_TMU_MODE_HIFI_UNI;387		} else if (rate) {388			sw->tmu.mode = TB_SWITCH_TMU_MODE_HIFI_BI;389		}390	} else if (rate) {391		sw->tmu.mode = TB_SWITCH_TMU_MODE_HIFI_BI;392	}393 394	/* Update the initial request to match the current mode */395	sw->tmu.mode_request = sw->tmu.mode;396	sw->tmu.has_ucap = ucap;397 398	return 0;399}400 401/**402 * tb_switch_tmu_init() - Initialize switch TMU structures403 * @sw: Switch to initialized404 *405 * This function must be called before other TMU related functions to406 * makes the internal structures are filled in correctly. Does not407 * change any hardware configuration.408 */409int tb_switch_tmu_init(struct tb_switch *sw)410{411	struct tb_port *port;412	int ret;413 414	if (tb_switch_is_icm(sw))415		return 0;416 417	ret = tb_switch_find_cap(sw, TB_SWITCH_CAP_TMU);418	if (ret > 0)419		sw->tmu.cap = ret;420 421	tb_switch_for_each_port(sw, port) {422		int cap;423 424		cap = tb_port_find_cap(port, TB_PORT_CAP_TIME1);425		if (cap > 0)426			port->cap_tmu = cap;427	}428 429	ret = tmu_mode_init(sw);430	if (ret)431		return ret;432 433	tb_sw_dbg(sw, "TMU: current mode: %s\n", tmu_mode_name(sw->tmu.mode));434	return 0;435}436 437/**438 * tb_switch_tmu_post_time() - Update switch local time439 * @sw: Switch whose time to update440 *441 * Updates switch local time using time posting procedure.442 */443int tb_switch_tmu_post_time(struct tb_switch *sw)444{445	unsigned int post_time_high_offset, post_time_high = 0;446	unsigned int post_local_time_offset, post_time_offset;447	struct tb_switch *root_switch = sw->tb->root_switch;448	u64 hi, mid, lo, local_time, post_time;449	int i, ret, retries = 100;450	u32 gm_local_time[3];451 452	if (!tb_route(sw))453		return 0;454 455	if (!tb_switch_is_usb4(sw))456		return 0;457 458	/* Need to be able to read the grand master time */459	if (!root_switch->tmu.cap)460		return 0;461 462	ret = tb_sw_read(root_switch, gm_local_time, TB_CFG_SWITCH,463			 root_switch->tmu.cap + TMU_RTR_CS_1,464			 ARRAY_SIZE(gm_local_time));465	if (ret)466		return ret;467 468	for (i = 0; i < ARRAY_SIZE(gm_local_time); i++)469		tb_sw_dbg(root_switch, "TMU: local_time[%d]=0x%08x\n", i,470			  gm_local_time[i]);471 472	/* Convert to nanoseconds (drop fractional part) */473	hi = gm_local_time[2] & TMU_RTR_CS_3_LOCAL_TIME_NS_MASK;474	mid = gm_local_time[1];475	lo = (gm_local_time[0] & TMU_RTR_CS_1_LOCAL_TIME_NS_MASK) >>476		TMU_RTR_CS_1_LOCAL_TIME_NS_SHIFT;477	local_time = hi << 48 | mid << 16 | lo;478 479	/* Tell the switch that time sync is disrupted for a while */480	ret = tb_switch_tmu_set_time_disruption(sw, true);481	if (ret)482		return ret;483 484	post_local_time_offset = sw->tmu.cap + TMU_RTR_CS_22;485	post_time_offset = sw->tmu.cap + TMU_RTR_CS_24;486	post_time_high_offset = sw->tmu.cap + TMU_RTR_CS_25;487 488	/*489	 * Write the Grandmaster time to the Post Local Time registers490	 * of the new switch.491	 */492	ret = tb_sw_write(sw, &local_time, TB_CFG_SWITCH,493			  post_local_time_offset, 2);494	if (ret)495		goto out;496 497	/*498	 * Have the new switch update its local time by:499	 * 1) writing 0x1 to the Post Time Low register and 0xffffffff to500	 * Post Time High register.501	 * 2) write 0 to Post Time High register and then wait for502	 * the completion of the post_time register becomes 0.503	 * This means the time has been converged properly.504	 */505	post_time = 0xffffffff00000001ULL;506 507	ret = tb_sw_write(sw, &post_time, TB_CFG_SWITCH, post_time_offset, 2);508	if (ret)509		goto out;510 511	ret = tb_sw_write(sw, &post_time_high, TB_CFG_SWITCH,512			  post_time_high_offset, 1);513	if (ret)514		goto out;515 516	do {517		usleep_range(5, 10);518		ret = tb_sw_read(sw, &post_time, TB_CFG_SWITCH,519				 post_time_offset, 2);520		if (ret)521			goto out;522	} while (--retries && post_time);523 524	if (!retries) {525		ret = -ETIMEDOUT;526		goto out;527	}528 529	tb_sw_dbg(sw, "TMU: updated local time to %#llx\n", local_time);530 531out:532	tb_switch_tmu_set_time_disruption(sw, false);533	return ret;534}535 536static int disable_enhanced(struct tb_port *up, struct tb_port *down)537{538	int ret;539 540	/*541	 * Router may already been disconnected so ignore errors on the542	 * upstream port.543	 */544	tb_port_tmu_rate_write(up, 0);545	tb_port_tmu_enhanced_enable(up, false);546 547	ret = tb_port_tmu_rate_write(down, 0);548	if (ret)549		return ret;550	return tb_port_tmu_enhanced_enable(down, false);551}552 553/**554 * tb_switch_tmu_disable() - Disable TMU of a switch555 * @sw: Switch whose TMU to disable556 *557 * Turns off TMU of @sw if it is enabled. If not enabled does nothing.558 */559int tb_switch_tmu_disable(struct tb_switch *sw)560{561	/* Already disabled? */562	if (sw->tmu.mode == TB_SWITCH_TMU_MODE_OFF)563		return 0;564 565	if (tb_route(sw)) {566		struct tb_port *down, *up;567		int ret;568 569		down = tb_switch_downstream_port(sw);570		up = tb_upstream_port(sw);571		/*572		 * In case of uni-directional time sync, TMU handshake is573		 * initiated by upstream router. In case of bi-directional574		 * time sync, TMU handshake is initiated by downstream router.575		 * We change downstream router's rate to off for both uni/bidir576		 * cases although it is needed only for the bi-directional mode.577		 * We avoid changing upstream router's mode since it might578		 * have another downstream router plugged, that is set to579		 * uni-directional mode and we don't want to change it's TMU580		 * mode.581		 */582		ret = tb_switch_tmu_rate_write(sw, tmu_rates[TB_SWITCH_TMU_MODE_OFF]);583		if (ret)584			return ret;585 586		tb_port_tmu_time_sync_disable(up);587		ret = tb_port_tmu_time_sync_disable(down);588		if (ret)589			return ret;590 591		switch (sw->tmu.mode) {592		case TB_SWITCH_TMU_MODE_LOWRES:593		case TB_SWITCH_TMU_MODE_HIFI_UNI:594			/* The switch may be unplugged so ignore any errors */595			tb_port_tmu_unidirectional_disable(up);596			ret = tb_port_tmu_unidirectional_disable(down);597			if (ret)598				return ret;599			break;600 601		case TB_SWITCH_TMU_MODE_MEDRES_ENHANCED_UNI:602			ret = disable_enhanced(up, down);603			if (ret)604				return ret;605			break;606 607		default:608			break;609		}610	} else {611		tb_switch_tmu_rate_write(sw, tmu_rates[TB_SWITCH_TMU_MODE_OFF]);612	}613 614	sw->tmu.mode = TB_SWITCH_TMU_MODE_OFF;615 616	tb_sw_dbg(sw, "TMU: disabled\n");617	return 0;618}619 620/* Called only when there is failure enabling requested mode */621static void tb_switch_tmu_off(struct tb_switch *sw)622{623	unsigned int rate = tmu_rates[TB_SWITCH_TMU_MODE_OFF];624	struct tb_port *down, *up;625 626	down = tb_switch_downstream_port(sw);627	up = tb_upstream_port(sw);628	/*629	 * In case of any failure in one of the steps when setting630	 * bi-directional or uni-directional TMU mode, get back to the TMU631	 * configurations in off mode. In case of additional failures in632	 * the functions below, ignore them since the caller shall already633	 * report a failure.634	 */635	tb_port_tmu_time_sync_disable(down);636	tb_port_tmu_time_sync_disable(up);637 638	switch (sw->tmu.mode_request) {639	case TB_SWITCH_TMU_MODE_LOWRES:640	case TB_SWITCH_TMU_MODE_HIFI_UNI:641		tb_switch_tmu_rate_write(tb_switch_parent(sw), rate);642		break;643	case TB_SWITCH_TMU_MODE_MEDRES_ENHANCED_UNI:644		disable_enhanced(up, down);645		break;646	default:647		break;648	}649 650	/* Always set the rate to 0 */651	tb_switch_tmu_rate_write(sw, rate);652 653	tb_switch_set_tmu_mode_params(sw, sw->tmu.mode);654	tb_port_tmu_unidirectional_disable(down);655	tb_port_tmu_unidirectional_disable(up);656}657 658/*659 * This function is called when the previous TMU mode was660 * TB_SWITCH_TMU_MODE_OFF.661 */662static int tb_switch_tmu_enable_bidirectional(struct tb_switch *sw)663{664	struct tb_port *up, *down;665	int ret;666 667	up = tb_upstream_port(sw);668	down = tb_switch_downstream_port(sw);669 670	ret = tb_port_tmu_unidirectional_disable(up);671	if (ret)672		return ret;673 674	ret = tb_port_tmu_unidirectional_disable(down);675	if (ret)676		goto out;677 678	ret = tb_switch_tmu_rate_write(sw, tmu_rates[TB_SWITCH_TMU_MODE_HIFI_BI]);679	if (ret)680		goto out;681 682	ret = tb_port_tmu_time_sync_enable(up);683	if (ret)684		goto out;685 686	ret = tb_port_tmu_time_sync_enable(down);687	if (ret)688		goto out;689 690	return 0;691 692out:693	tb_switch_tmu_off(sw);694	return ret;695}696 697/* Only needed for Titan Ridge */698static int tb_switch_tmu_disable_objections(struct tb_switch *sw)699{700	struct tb_port *up = tb_upstream_port(sw);701	u32 val;702	int ret;703 704	ret = tb_sw_read(sw, &val, TB_CFG_SWITCH,705			 sw->cap_vsec_tmu + TB_TIME_VSEC_3_CS_9, 1);706	if (ret)707		return ret;708 709	val &= ~TB_TIME_VSEC_3_CS_9_TMU_OBJ_MASK;710 711	ret = tb_sw_write(sw, &val, TB_CFG_SWITCH,712			  sw->cap_vsec_tmu + TB_TIME_VSEC_3_CS_9, 1);713	if (ret)714		return ret;715 716	return tb_port_tmu_write(up, TMU_ADP_CS_6,717				 TMU_ADP_CS_6_DISABLE_TMU_OBJ_MASK,718				 TMU_ADP_CS_6_DISABLE_TMU_OBJ_CL1 |719				 TMU_ADP_CS_6_DISABLE_TMU_OBJ_CL2);720}721 722/*723 * This function is called when the previous TMU mode was724 * TB_SWITCH_TMU_MODE_OFF.725 */726static int tb_switch_tmu_enable_unidirectional(struct tb_switch *sw)727{728	struct tb_port *up, *down;729	int ret;730 731	up = tb_upstream_port(sw);732	down = tb_switch_downstream_port(sw);733	ret = tb_switch_tmu_rate_write(tb_switch_parent(sw),734				       tmu_rates[sw->tmu.mode_request]);735	if (ret)736		return ret;737 738	ret = tb_switch_set_tmu_mode_params(sw, sw->tmu.mode_request);739	if (ret)740		return ret;741 742	ret = tb_port_tmu_unidirectional_enable(up);743	if (ret)744		goto out;745 746	ret = tb_port_tmu_time_sync_enable(up);747	if (ret)748		goto out;749 750	ret = tb_port_tmu_unidirectional_enable(down);751	if (ret)752		goto out;753 754	ret = tb_port_tmu_time_sync_enable(down);755	if (ret)756		goto out;757 758	return 0;759 760out:761	tb_switch_tmu_off(sw);762	return ret;763}764 765/*766 * This function is called when the previous TMU mode was767 * TB_SWITCH_TMU_RATE_OFF.768 */769static int tb_switch_tmu_enable_enhanced(struct tb_switch *sw)770{771	unsigned int rate = tmu_rates[sw->tmu.mode_request];772	struct tb_port *up, *down;773	int ret;774 775	/* Router specific parameters first */776	ret = tb_switch_set_tmu_mode_params(sw, sw->tmu.mode_request);777	if (ret)778		return ret;779 780	up = tb_upstream_port(sw);781	down = tb_switch_downstream_port(sw);782 783	ret = tb_port_set_tmu_mode_params(up, sw->tmu.mode_request);784	if (ret)785		goto out;786 787	ret = tb_port_tmu_rate_write(up, rate);788	if (ret)789		goto out;790 791	ret = tb_port_tmu_enhanced_enable(up, true);792	if (ret)793		goto out;794 795	ret = tb_port_set_tmu_mode_params(down, sw->tmu.mode_request);796	if (ret)797		goto out;798 799	ret = tb_port_tmu_rate_write(down, rate);800	if (ret)801		goto out;802 803	ret = tb_port_tmu_enhanced_enable(down, true);804	if (ret)805		goto out;806 807	return 0;808 809out:810	tb_switch_tmu_off(sw);811	return ret;812}813 814static void tb_switch_tmu_change_mode_prev(struct tb_switch *sw)815{816	unsigned int rate = tmu_rates[sw->tmu.mode];817	struct tb_port *down, *up;818 819	down = tb_switch_downstream_port(sw);820	up = tb_upstream_port(sw);821	/*822	 * In case of any failure in one of the steps when change mode,823	 * get back to the TMU configurations in previous mode.824	 * In case of additional failures in the functions below,825	 * ignore them since the caller shall already report a failure.826	 */827	switch (sw->tmu.mode) {828	case TB_SWITCH_TMU_MODE_LOWRES:829	case TB_SWITCH_TMU_MODE_HIFI_UNI:830		tb_port_tmu_set_unidirectional(down, true);831		tb_switch_tmu_rate_write(tb_switch_parent(sw), rate);832		break;833 834	case TB_SWITCH_TMU_MODE_HIFI_BI:835		tb_port_tmu_set_unidirectional(down, false);836		tb_switch_tmu_rate_write(sw, rate);837		break;838 839	default:840		break;841	}842 843	tb_switch_set_tmu_mode_params(sw, sw->tmu.mode);844 845	switch (sw->tmu.mode) {846	case TB_SWITCH_TMU_MODE_LOWRES:847	case TB_SWITCH_TMU_MODE_HIFI_UNI:848		tb_port_tmu_set_unidirectional(up, true);849		break;850 851	case TB_SWITCH_TMU_MODE_HIFI_BI:852		tb_port_tmu_set_unidirectional(up, false);853		break;854 855	default:856		break;857	}858}859 860static int tb_switch_tmu_change_mode(struct tb_switch *sw)861{862	unsigned int rate = tmu_rates[sw->tmu.mode_request];863	struct tb_port *up, *down;864	int ret;865 866	up = tb_upstream_port(sw);867	down = tb_switch_downstream_port(sw);868 869	/* Program the upstream router downstream facing lane adapter */870	switch (sw->tmu.mode_request) {871	case TB_SWITCH_TMU_MODE_LOWRES:872	case TB_SWITCH_TMU_MODE_HIFI_UNI:873		ret = tb_port_tmu_set_unidirectional(down, true);874		if (ret)875			goto out;876		ret = tb_switch_tmu_rate_write(tb_switch_parent(sw), rate);877		if (ret)878			goto out;879		break;880 881	case TB_SWITCH_TMU_MODE_HIFI_BI:882		ret = tb_port_tmu_set_unidirectional(down, false);883		if (ret)884			goto out;885		ret = tb_switch_tmu_rate_write(sw, rate);886		if (ret)887			goto out;888		break;889 890	default:891		/* Not allowed to change modes from other than above */892		return -EINVAL;893	}894 895	ret = tb_switch_set_tmu_mode_params(sw, sw->tmu.mode_request);896	if (ret)897		goto out;898 899	/* Program the new mode and the downstream router lane adapter */900	switch (sw->tmu.mode_request) {901	case TB_SWITCH_TMU_MODE_LOWRES:902	case TB_SWITCH_TMU_MODE_HIFI_UNI:903		ret = tb_port_tmu_set_unidirectional(up, true);904		if (ret)905			goto out;906		break;907 908	case TB_SWITCH_TMU_MODE_HIFI_BI:909		ret = tb_port_tmu_set_unidirectional(up, false);910		if (ret)911			goto out;912		break;913 914	default:915		/* Not allowed to change modes from other than above */916		return -EINVAL;917	}918 919	ret = tb_port_tmu_time_sync_enable(down);920	if (ret)921		goto out;922 923	ret = tb_port_tmu_time_sync_enable(up);924	if (ret)925		goto out;926 927	return 0;928 929out:930	tb_switch_tmu_change_mode_prev(sw);931	return ret;932}933 934/**935 * tb_switch_tmu_enable() - Enable TMU on a router936 * @sw: Router whose TMU to enable937 *938 * Enables TMU of a router to be in uni-directional Normal/HiFi or939 * bi-directional HiFi mode. Calling tb_switch_tmu_configure() is940 * required before calling this function.941 */942int tb_switch_tmu_enable(struct tb_switch *sw)943{944	int ret;945 946	if (tb_switch_tmu_is_enabled(sw))947		return 0;948 949	if (tb_switch_is_titan_ridge(sw) &&950	    (sw->tmu.mode_request == TB_SWITCH_TMU_MODE_LOWRES ||951	     sw->tmu.mode_request == TB_SWITCH_TMU_MODE_HIFI_UNI)) {952		ret = tb_switch_tmu_disable_objections(sw);953		if (ret)954			return ret;955	}956 957	ret = tb_switch_tmu_set_time_disruption(sw, true);958	if (ret)959		return ret;960 961	if (tb_route(sw)) {962		/*963		 * The used mode changes are from OFF to964		 * HiFi-Uni/HiFi-BiDir/Normal-Uni or from Normal-Uni to965		 * HiFi-Uni.966		 */967		if (sw->tmu.mode == TB_SWITCH_TMU_MODE_OFF) {968			switch (sw->tmu.mode_request) {969			case TB_SWITCH_TMU_MODE_LOWRES:970			case TB_SWITCH_TMU_MODE_HIFI_UNI:971				ret = tb_switch_tmu_enable_unidirectional(sw);972				break;973 974			case TB_SWITCH_TMU_MODE_HIFI_BI:975				ret = tb_switch_tmu_enable_bidirectional(sw);976				break;977			case TB_SWITCH_TMU_MODE_MEDRES_ENHANCED_UNI:978				ret = tb_switch_tmu_enable_enhanced(sw);979				break;980			default:981				ret = -EINVAL;982				break;983			}984		} else if (sw->tmu.mode == TB_SWITCH_TMU_MODE_LOWRES ||985			   sw->tmu.mode == TB_SWITCH_TMU_MODE_HIFI_UNI ||986			   sw->tmu.mode == TB_SWITCH_TMU_MODE_HIFI_BI) {987			ret = tb_switch_tmu_change_mode(sw);988		} else {989			ret = -EINVAL;990		}991	} else {992		/*993		 * Host router port configurations are written as994		 * part of configurations for downstream port of the parent995		 * of the child node - see above.996		 * Here only the host router' rate configuration is written.997		 */998		ret = tb_switch_tmu_rate_write(sw, tmu_rates[sw->tmu.mode_request]);999	}1000 1001	if (ret) {1002		tb_sw_warn(sw, "TMU: failed to enable mode %s: %d\n",1003			   tmu_mode_name(sw->tmu.mode_request), ret);1004	} else {1005		sw->tmu.mode = sw->tmu.mode_request;1006		tb_sw_dbg(sw, "TMU: mode set to: %s\n", tmu_mode_name(sw->tmu.mode));1007	}1008 1009	return tb_switch_tmu_set_time_disruption(sw, false);1010}1011 1012/**1013 * tb_switch_tmu_configure() - Configure the TMU mode1014 * @sw: Router whose mode to change1015 * @mode: Mode to configure1016 *1017 * Selects the TMU mode that is enabled when tb_switch_tmu_enable() is1018 * next called.1019 *1020 * Returns %0 in success and negative errno otherwise. Specifically1021 * returns %-EOPNOTSUPP if the requested mode is not possible (not1022 * supported by the router and/or topology).1023 */1024int tb_switch_tmu_configure(struct tb_switch *sw, enum tb_switch_tmu_mode mode)1025{1026	switch (mode) {1027	case TB_SWITCH_TMU_MODE_OFF:1028		break;1029 1030	case TB_SWITCH_TMU_MODE_LOWRES:1031	case TB_SWITCH_TMU_MODE_HIFI_UNI:1032		if (!sw->tmu.has_ucap)1033			return -EOPNOTSUPP;1034		break;1035 1036	case TB_SWITCH_TMU_MODE_HIFI_BI:1037		break;1038 1039	case TB_SWITCH_TMU_MODE_MEDRES_ENHANCED_UNI: {1040		const struct tb_switch *parent_sw = tb_switch_parent(sw);1041 1042		if (!parent_sw || !tb_switch_tmu_enhanced_is_supported(parent_sw))1043			return -EOPNOTSUPP;1044		if (!tb_switch_tmu_enhanced_is_supported(sw))1045			return -EOPNOTSUPP;1046 1047		break;1048	}1049 1050	default:1051		tb_sw_warn(sw, "TMU: unsupported mode %u\n", mode);1052		return -EINVAL;1053	}1054 1055	if (sw->tmu.mode_request != mode) {1056		tb_sw_dbg(sw, "TMU: mode change %s -> %s requested\n",1057			  tmu_mode_name(sw->tmu.mode), tmu_mode_name(mode));1058		sw->tmu.mode_request = mode;1059	}1060 1061	return 0;1062}1063