xref: /openbsd-src/sys/dev/pci/drm/i915/vlv_sideband.c (revision f005ef32267c16bdb134f0e9fa4477dbe07c263a)
11bb76ff1Sjsg // SPDX-License-Identifier: MIT
21bb76ff1Sjsg /*
31bb76ff1Sjsg  * Copyright © 2013-2021 Intel Corporation
41bb76ff1Sjsg  */
51bb76ff1Sjsg 
61bb76ff1Sjsg #include "i915_drv.h"
71bb76ff1Sjsg #include "i915_iosf_mbi.h"
81bb76ff1Sjsg #include "i915_reg.h"
91bb76ff1Sjsg #include "vlv_sideband.h"
101bb76ff1Sjsg 
11*f005ef32Sjsg #include "display/intel_dpio_phy.h"
12*f005ef32Sjsg #include "display/intel_display_types.h"
13*f005ef32Sjsg 
141bb76ff1Sjsg /*
151bb76ff1Sjsg  * IOSF sideband, see VLV2_SidebandMsg_HAS.docx and
161bb76ff1Sjsg  * VLV_VLV2_PUNIT_HAS_0.8.docx
171bb76ff1Sjsg  */
181bb76ff1Sjsg 
191bb76ff1Sjsg /* Standard MMIO read, non-posted */
201bb76ff1Sjsg #define SB_MRD_NP	0x00
211bb76ff1Sjsg /* Standard MMIO write, non-posted */
221bb76ff1Sjsg #define SB_MWR_NP	0x01
231bb76ff1Sjsg /* Private register read, double-word addressing, non-posted */
241bb76ff1Sjsg #define SB_CRRDDA_NP	0x06
251bb76ff1Sjsg /* Private register write, double-word addressing, non-posted */
261bb76ff1Sjsg #define SB_CRWRDA_NP	0x07
271bb76ff1Sjsg 
ping(void * info)281bb76ff1Sjsg static void ping(void *info)
291bb76ff1Sjsg {
301bb76ff1Sjsg }
311bb76ff1Sjsg 
__vlv_punit_get(struct drm_i915_private * i915)321bb76ff1Sjsg static void __vlv_punit_get(struct drm_i915_private *i915)
331bb76ff1Sjsg {
341bb76ff1Sjsg 	iosf_mbi_punit_acquire();
351bb76ff1Sjsg 
361bb76ff1Sjsg 	/*
371bb76ff1Sjsg 	 * Prevent the cpu from sleeping while we use this sideband, otherwise
381bb76ff1Sjsg 	 * the punit may cause a machine hang. The issue appears to be isolated
391bb76ff1Sjsg 	 * with changing the power state of the CPU package while changing
401bb76ff1Sjsg 	 * the power state via the punit, and we have only observed it
411bb76ff1Sjsg 	 * reliably on 4-core Baytail systems suggesting the issue is in the
421bb76ff1Sjsg 	 * power delivery mechanism and likely to be board/function
431bb76ff1Sjsg 	 * specific. Hence we presume the workaround needs only be applied
441bb76ff1Sjsg 	 * to the Valleyview P-unit and not all sideband communications.
451bb76ff1Sjsg 	 */
461bb76ff1Sjsg 	if (IS_VALLEYVIEW(i915)) {
471bb76ff1Sjsg 		cpu_latency_qos_update_request(&i915->sb_qos, 0);
481bb76ff1Sjsg #ifdef notyet
491bb76ff1Sjsg 		on_each_cpu(ping, NULL, 1);
501bb76ff1Sjsg #endif
511bb76ff1Sjsg 	}
521bb76ff1Sjsg }
531bb76ff1Sjsg 
__vlv_punit_put(struct drm_i915_private * i915)541bb76ff1Sjsg static void __vlv_punit_put(struct drm_i915_private *i915)
551bb76ff1Sjsg {
561bb76ff1Sjsg 	if (IS_VALLEYVIEW(i915))
571bb76ff1Sjsg 		cpu_latency_qos_update_request(&i915->sb_qos,
581bb76ff1Sjsg 					       PM_QOS_DEFAULT_VALUE);
591bb76ff1Sjsg 
601bb76ff1Sjsg 	iosf_mbi_punit_release();
611bb76ff1Sjsg }
621bb76ff1Sjsg 
vlv_iosf_sb_get(struct drm_i915_private * i915,unsigned long ports)631bb76ff1Sjsg void vlv_iosf_sb_get(struct drm_i915_private *i915, unsigned long ports)
641bb76ff1Sjsg {
651bb76ff1Sjsg 	if (ports & BIT(VLV_IOSF_SB_PUNIT))
661bb76ff1Sjsg 		__vlv_punit_get(i915);
671bb76ff1Sjsg 
681bb76ff1Sjsg 	mutex_lock(&i915->sb_lock);
691bb76ff1Sjsg }
701bb76ff1Sjsg 
vlv_iosf_sb_put(struct drm_i915_private * i915,unsigned long ports)711bb76ff1Sjsg void vlv_iosf_sb_put(struct drm_i915_private *i915, unsigned long ports)
721bb76ff1Sjsg {
731bb76ff1Sjsg 	mutex_unlock(&i915->sb_lock);
741bb76ff1Sjsg 
751bb76ff1Sjsg 	if (ports & BIT(VLV_IOSF_SB_PUNIT))
761bb76ff1Sjsg 		__vlv_punit_put(i915);
771bb76ff1Sjsg }
781bb76ff1Sjsg 
vlv_sideband_rw(struct drm_i915_private * i915,u32 devfn,u32 port,u32 opcode,u32 addr,u32 * val)791bb76ff1Sjsg static int vlv_sideband_rw(struct drm_i915_private *i915,
801bb76ff1Sjsg 			   u32 devfn, u32 port, u32 opcode,
811bb76ff1Sjsg 			   u32 addr, u32 *val)
821bb76ff1Sjsg {
831bb76ff1Sjsg 	struct intel_uncore *uncore = &i915->uncore;
841bb76ff1Sjsg 	const bool is_read = (opcode == SB_MRD_NP || opcode == SB_CRRDDA_NP);
851bb76ff1Sjsg 	int err;
861bb76ff1Sjsg 
871bb76ff1Sjsg 	lockdep_assert_held(&i915->sb_lock);
881bb76ff1Sjsg 	if (port == IOSF_PORT_PUNIT)
891bb76ff1Sjsg 		iosf_mbi_assert_punit_acquired();
901bb76ff1Sjsg 
911bb76ff1Sjsg 	/* Flush the previous comms, just in case it failed last time. */
921bb76ff1Sjsg 	if (intel_wait_for_register(uncore,
931bb76ff1Sjsg 				    VLV_IOSF_DOORBELL_REQ, IOSF_SB_BUSY, 0,
941bb76ff1Sjsg 				    5)) {
951bb76ff1Sjsg 		drm_dbg(&i915->drm, "IOSF sideband idle wait (%s) timed out\n",
961bb76ff1Sjsg 			is_read ? "read" : "write");
971bb76ff1Sjsg 		return -EAGAIN;
981bb76ff1Sjsg 	}
991bb76ff1Sjsg 
1001bb76ff1Sjsg 	preempt_disable();
1011bb76ff1Sjsg 
1021bb76ff1Sjsg 	intel_uncore_write_fw(uncore, VLV_IOSF_ADDR, addr);
1031bb76ff1Sjsg 	intel_uncore_write_fw(uncore, VLV_IOSF_DATA, is_read ? 0 : *val);
1041bb76ff1Sjsg 	intel_uncore_write_fw(uncore, VLV_IOSF_DOORBELL_REQ,
1051bb76ff1Sjsg 			      (devfn << IOSF_DEVFN_SHIFT) |
1061bb76ff1Sjsg 			      (opcode << IOSF_OPCODE_SHIFT) |
1071bb76ff1Sjsg 			      (port << IOSF_PORT_SHIFT) |
1081bb76ff1Sjsg 			      (0xf << IOSF_BYTE_ENABLES_SHIFT) |
1091bb76ff1Sjsg 			      (0 << IOSF_BAR_SHIFT) |
1101bb76ff1Sjsg 			      IOSF_SB_BUSY);
1111bb76ff1Sjsg 
1121bb76ff1Sjsg 	if (__intel_wait_for_register_fw(uncore,
1131bb76ff1Sjsg 					 VLV_IOSF_DOORBELL_REQ, IOSF_SB_BUSY, 0,
1141bb76ff1Sjsg 					 10000, 0, NULL) == 0) {
1151bb76ff1Sjsg 		if (is_read)
1161bb76ff1Sjsg 			*val = intel_uncore_read_fw(uncore, VLV_IOSF_DATA);
1171bb76ff1Sjsg 		err = 0;
1181bb76ff1Sjsg 	} else {
1191bb76ff1Sjsg 		drm_dbg(&i915->drm, "IOSF sideband finish wait (%s) timed out\n",
1201bb76ff1Sjsg 			is_read ? "read" : "write");
1211bb76ff1Sjsg 		err = -ETIMEDOUT;
1221bb76ff1Sjsg 	}
1231bb76ff1Sjsg 
1241bb76ff1Sjsg 	preempt_enable();
1251bb76ff1Sjsg 
1261bb76ff1Sjsg 	return err;
1271bb76ff1Sjsg }
1281bb76ff1Sjsg 
vlv_punit_read(struct drm_i915_private * i915,u32 addr)1291bb76ff1Sjsg u32 vlv_punit_read(struct drm_i915_private *i915, u32 addr)
1301bb76ff1Sjsg {
1311bb76ff1Sjsg 	u32 val = 0;
1321bb76ff1Sjsg 
1331bb76ff1Sjsg 	vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_PUNIT,
1341bb76ff1Sjsg 			SB_CRRDDA_NP, addr, &val);
1351bb76ff1Sjsg 
1361bb76ff1Sjsg 	return val;
1371bb76ff1Sjsg }
1381bb76ff1Sjsg 
vlv_punit_write(struct drm_i915_private * i915,u32 addr,u32 val)1391bb76ff1Sjsg int vlv_punit_write(struct drm_i915_private *i915, u32 addr, u32 val)
1401bb76ff1Sjsg {
1411bb76ff1Sjsg 	return vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_PUNIT,
1421bb76ff1Sjsg 			       SB_CRWRDA_NP, addr, &val);
1431bb76ff1Sjsg }
1441bb76ff1Sjsg 
vlv_bunit_read(struct drm_i915_private * i915,u32 reg)1451bb76ff1Sjsg u32 vlv_bunit_read(struct drm_i915_private *i915, u32 reg)
1461bb76ff1Sjsg {
1471bb76ff1Sjsg 	u32 val = 0;
1481bb76ff1Sjsg 
1491bb76ff1Sjsg 	vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_BUNIT,
1501bb76ff1Sjsg 			SB_CRRDDA_NP, reg, &val);
1511bb76ff1Sjsg 
1521bb76ff1Sjsg 	return val;
1531bb76ff1Sjsg }
1541bb76ff1Sjsg 
vlv_bunit_write(struct drm_i915_private * i915,u32 reg,u32 val)1551bb76ff1Sjsg void vlv_bunit_write(struct drm_i915_private *i915, u32 reg, u32 val)
1561bb76ff1Sjsg {
1571bb76ff1Sjsg 	vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_BUNIT,
1581bb76ff1Sjsg 			SB_CRWRDA_NP, reg, &val);
1591bb76ff1Sjsg }
1601bb76ff1Sjsg 
vlv_nc_read(struct drm_i915_private * i915,u8 addr)1611bb76ff1Sjsg u32 vlv_nc_read(struct drm_i915_private *i915, u8 addr)
1621bb76ff1Sjsg {
1631bb76ff1Sjsg 	u32 val = 0;
1641bb76ff1Sjsg 
1651bb76ff1Sjsg 	vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_NC,
1661bb76ff1Sjsg 			SB_CRRDDA_NP, addr, &val);
1671bb76ff1Sjsg 
1681bb76ff1Sjsg 	return val;
1691bb76ff1Sjsg }
1701bb76ff1Sjsg 
vlv_iosf_sb_read(struct drm_i915_private * i915,u8 port,u32 reg)1711bb76ff1Sjsg u32 vlv_iosf_sb_read(struct drm_i915_private *i915, u8 port, u32 reg)
1721bb76ff1Sjsg {
1731bb76ff1Sjsg 	u32 val = 0;
1741bb76ff1Sjsg 
1751bb76ff1Sjsg 	vlv_sideband_rw(i915, PCI_DEVFN(0, 0), port,
1761bb76ff1Sjsg 			SB_CRRDDA_NP, reg, &val);
1771bb76ff1Sjsg 
1781bb76ff1Sjsg 	return val;
1791bb76ff1Sjsg }
1801bb76ff1Sjsg 
vlv_iosf_sb_write(struct drm_i915_private * i915,u8 port,u32 reg,u32 val)1811bb76ff1Sjsg void vlv_iosf_sb_write(struct drm_i915_private *i915,
1821bb76ff1Sjsg 		       u8 port, u32 reg, u32 val)
1831bb76ff1Sjsg {
1841bb76ff1Sjsg 	vlv_sideband_rw(i915, PCI_DEVFN(0, 0), port,
1851bb76ff1Sjsg 			SB_CRWRDA_NP, reg, &val);
1861bb76ff1Sjsg }
1871bb76ff1Sjsg 
vlv_cck_read(struct drm_i915_private * i915,u32 reg)1881bb76ff1Sjsg u32 vlv_cck_read(struct drm_i915_private *i915, u32 reg)
1891bb76ff1Sjsg {
1901bb76ff1Sjsg 	u32 val = 0;
1911bb76ff1Sjsg 
1921bb76ff1Sjsg 	vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCK,
1931bb76ff1Sjsg 			SB_CRRDDA_NP, reg, &val);
1941bb76ff1Sjsg 
1951bb76ff1Sjsg 	return val;
1961bb76ff1Sjsg }
1971bb76ff1Sjsg 
vlv_cck_write(struct drm_i915_private * i915,u32 reg,u32 val)1981bb76ff1Sjsg void vlv_cck_write(struct drm_i915_private *i915, u32 reg, u32 val)
1991bb76ff1Sjsg {
2001bb76ff1Sjsg 	vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCK,
2011bb76ff1Sjsg 			SB_CRWRDA_NP, reg, &val);
2021bb76ff1Sjsg }
2031bb76ff1Sjsg 
vlv_ccu_read(struct drm_i915_private * i915,u32 reg)2041bb76ff1Sjsg u32 vlv_ccu_read(struct drm_i915_private *i915, u32 reg)
2051bb76ff1Sjsg {
2061bb76ff1Sjsg 	u32 val = 0;
2071bb76ff1Sjsg 
2081bb76ff1Sjsg 	vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCU,
2091bb76ff1Sjsg 			SB_CRRDDA_NP, reg, &val);
2101bb76ff1Sjsg 
2111bb76ff1Sjsg 	return val;
2121bb76ff1Sjsg }
2131bb76ff1Sjsg 
vlv_ccu_write(struct drm_i915_private * i915,u32 reg,u32 val)2141bb76ff1Sjsg void vlv_ccu_write(struct drm_i915_private *i915, u32 reg, u32 val)
2151bb76ff1Sjsg {
2161bb76ff1Sjsg 	vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCU,
2171bb76ff1Sjsg 			SB_CRWRDA_NP, reg, &val);
2181bb76ff1Sjsg }
2191bb76ff1Sjsg 
vlv_dpio_phy_iosf_port(struct drm_i915_private * i915,enum dpio_phy phy)2201bb76ff1Sjsg static u32 vlv_dpio_phy_iosf_port(struct drm_i915_private *i915, enum dpio_phy phy)
2211bb76ff1Sjsg {
2221bb76ff1Sjsg 	/*
2231bb76ff1Sjsg 	 * IOSF_PORT_DPIO: VLV x2 PHY (DP/HDMI B and C), CHV x1 PHY (DP/HDMI D)
2241bb76ff1Sjsg 	 * IOSF_PORT_DPIO_2: CHV x2 PHY (DP/HDMI B and C)
2251bb76ff1Sjsg 	 */
2261bb76ff1Sjsg 	if (IS_CHERRYVIEW(i915))
2271bb76ff1Sjsg 		return phy == DPIO_PHY0 ? IOSF_PORT_DPIO_2 : IOSF_PORT_DPIO;
2281bb76ff1Sjsg 	else
2291bb76ff1Sjsg 		return IOSF_PORT_DPIO;
2301bb76ff1Sjsg }
2311bb76ff1Sjsg 
vlv_dpio_read(struct drm_i915_private * i915,enum pipe pipe,int reg)2321bb76ff1Sjsg u32 vlv_dpio_read(struct drm_i915_private *i915, enum pipe pipe, int reg)
2331bb76ff1Sjsg {
2341bb76ff1Sjsg 	u32 port = vlv_dpio_phy_iosf_port(i915, DPIO_PHY(pipe));
2351bb76ff1Sjsg 	u32 val = 0;
2361bb76ff1Sjsg 
2371bb76ff1Sjsg 	vlv_sideband_rw(i915, DPIO_DEVFN, port, SB_MRD_NP, reg, &val);
2381bb76ff1Sjsg 
2391bb76ff1Sjsg 	/*
2401bb76ff1Sjsg 	 * FIXME: There might be some registers where all 1's is a valid value,
2411bb76ff1Sjsg 	 * so ideally we should check the register offset instead...
2421bb76ff1Sjsg 	 */
2431bb76ff1Sjsg 	drm_WARN(&i915->drm, val == 0xffffffff,
2441bb76ff1Sjsg 		 "DPIO read pipe %c reg 0x%x == 0x%x\n",
2451bb76ff1Sjsg 		 pipe_name(pipe), reg, val);
2461bb76ff1Sjsg 
2471bb76ff1Sjsg 	return val;
2481bb76ff1Sjsg }
2491bb76ff1Sjsg 
vlv_dpio_write(struct drm_i915_private * i915,enum pipe pipe,int reg,u32 val)2501bb76ff1Sjsg void vlv_dpio_write(struct drm_i915_private *i915,
2511bb76ff1Sjsg 		    enum pipe pipe, int reg, u32 val)
2521bb76ff1Sjsg {
2531bb76ff1Sjsg 	u32 port = vlv_dpio_phy_iosf_port(i915, DPIO_PHY(pipe));
2541bb76ff1Sjsg 
2551bb76ff1Sjsg 	vlv_sideband_rw(i915, DPIO_DEVFN, port, SB_MWR_NP, reg, &val);
2561bb76ff1Sjsg }
2571bb76ff1Sjsg 
vlv_flisdsi_read(struct drm_i915_private * i915,u32 reg)2581bb76ff1Sjsg u32 vlv_flisdsi_read(struct drm_i915_private *i915, u32 reg)
2591bb76ff1Sjsg {
2601bb76ff1Sjsg 	u32 val = 0;
2611bb76ff1Sjsg 
2621bb76ff1Sjsg 	vlv_sideband_rw(i915, DPIO_DEVFN, IOSF_PORT_FLISDSI, SB_CRRDDA_NP,
2631bb76ff1Sjsg 			reg, &val);
2641bb76ff1Sjsg 	return val;
2651bb76ff1Sjsg }
2661bb76ff1Sjsg 
vlv_flisdsi_write(struct drm_i915_private * i915,u32 reg,u32 val)2671bb76ff1Sjsg void vlv_flisdsi_write(struct drm_i915_private *i915, u32 reg, u32 val)
2681bb76ff1Sjsg {
2691bb76ff1Sjsg 	vlv_sideband_rw(i915, DPIO_DEVFN, IOSF_PORT_FLISDSI, SB_CRWRDA_NP,
2701bb76ff1Sjsg 			reg, &val);
2711bb76ff1Sjsg }
272