1 #include <unistd.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <err.h>
5 #include <errno.h>
6 
7 #include "intel_io.h"
8 #include "intel_reg.h"
9 #include "igt_core.h"
10 
11 #define TIMEOUT_US 500000
12 
13 /* Standard MMIO read, non-posted */
14 #define SB_MRD_NP      0x00
15 /* Standard MMIO write, non-posted */
16 #define SB_MWR_NP      0x01
17 /* Private register read, double-word addressing, non-posted */
18 #define SB_CRRDDA_NP   0x06
19 /* Private register write, double-word addressing, non-posted */
20 #define SB_CRWRDA_NP   0x07
21 
vlv_sideband_rw(uint32_t port,uint8_t opcode,uint32_t addr,uint32_t * val)22 static int vlv_sideband_rw(uint32_t port, uint8_t opcode, uint32_t addr,
23 			   uint32_t *val)
24 {
25 	int timeout = 0;
26 	uint32_t cmd, devfn, be, bar;
27 	int is_read = (opcode == SB_CRRDDA_NP || opcode == SB_MRD_NP);
28 
29 	bar = 0;
30 	be = 0xf;
31 	devfn = 0;
32 
33 	cmd = (devfn << IOSF_DEVFN_SHIFT) | (opcode << IOSF_OPCODE_SHIFT) |
34 		(port << IOSF_PORT_SHIFT) | (be << IOSF_BYTE_ENABLES_SHIFT) |
35 		(bar << IOSF_BAR_SHIFT);
36 
37 	if (intel_register_read(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) {
38 		igt_warn("warning: pcode (%s) mailbox access failed\n", is_read ? "read" : "write");
39 		return -EAGAIN;
40 	}
41 
42 	intel_register_write(VLV_IOSF_ADDR, addr);
43 	if (!is_read)
44 		intel_register_write(VLV_IOSF_DATA, *val);
45 
46 	intel_register_write(VLV_IOSF_DOORBELL_REQ, cmd);
47 
48 	do {
49 		usleep(1);
50 		timeout++;
51 	} while (intel_register_read(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY &&
52 		 timeout < TIMEOUT_US);
53 
54 	if (timeout >= TIMEOUT_US) {
55 		igt_warn("timeout waiting for pcode %s (%d) to finish\n", is_read ? "read" : "write", addr);
56 		return -ETIMEDOUT;
57 	}
58 
59 	if (is_read)
60 		*val = intel_register_read(VLV_IOSF_DATA);
61 	intel_register_write(VLV_IOSF_DATA, 0);
62 
63 	return 0;
64 }
65 
66 /**
67  * intel_punit_read:
68  * @addr: register offset
69  * @val: pointer to store the read result
70  *
71  * 32-bit read of the register at @offset through the P-Unit sideband port.
72  *
73  * Returns:
74  * 0 when the register access succeeded, negative errno code on failure.
75  */
intel_punit_read(uint32_t addr,uint32_t * val)76 int intel_punit_read(uint32_t addr, uint32_t *val)
77 {
78 	return vlv_sideband_rw(IOSF_PORT_PUNIT, SB_CRRDDA_NP, addr, val);
79 }
80 
81 /**
82  * intel_punit_write:
83  * @addr: register offset
84  * @val: value to write
85  *
86  * 32-bit write of the register at @offset through the P-Unit sideband port.
87  *
88  * Returns:
89  * 0 when the register access succeeded, negative errno code on failure.
90  */
intel_punit_write(uint32_t addr,uint32_t val)91 int intel_punit_write(uint32_t addr, uint32_t val)
92 {
93 	return vlv_sideband_rw(IOSF_PORT_PUNIT, SB_CRWRDA_NP, addr, &val);
94 }
95 
96 /**
97  * intel_nc_read:
98  * @addr: register offset
99  * @val: pointer to starge for the read result
100  *
101  * 32-bit read of the register at @offset through the NC sideband port.
102  *
103  * Returns:
104  * 0 when the register access succeeded, negative errno code on failure.
105  */
intel_nc_read(uint32_t addr,uint32_t * val)106 int intel_nc_read(uint32_t addr, uint32_t *val)
107 {
108 	return vlv_sideband_rw(IOSF_PORT_NC, SB_CRRDDA_NP, addr, val);
109 }
110 
111 /**
112  * intel_nc_write:
113  * @addr: register offset
114  * @val: value to write
115  *
116  * 32-bit write of the register at @offset through the NC sideband port.
117  *
118  * Returns:
119  * 0 when the register access succeeded, negative errno code on failure.
120  */
intel_nc_write(uint32_t addr,uint32_t val)121 int intel_nc_write(uint32_t addr, uint32_t val)
122 {
123 	return vlv_sideband_rw(IOSF_PORT_NC, SB_CRWRDA_NP, addr, &val);
124 }
125 
126 /**
127  * intel_dpio_reg_read:
128  * @reg: register offset
129  * @phy: DPIO PHY to use
130  *
131  * 32-bit read of the register at @offset through the DPIO sideband port.
132  *
133  * Returns:
134  * The value read from the register.
135  */
intel_dpio_reg_read(uint32_t reg,int phy)136 uint32_t intel_dpio_reg_read(uint32_t reg, int phy)
137 {
138 	uint32_t val;
139 
140 	if (phy == 0)
141 		vlv_sideband_rw(IOSF_PORT_DPIO, SB_MRD_NP, reg, &val);
142 	else
143 		vlv_sideband_rw(IOSF_PORT_DPIO_2, SB_MRD_NP, reg, &val);
144 	return val;
145 }
146 
147 /**
148  * intel_dpio_reg_write:
149  * @reg: register offset
150  * @val: value to write
151  * @phy: dpio PHY to use
152  *
153  * 32-bit write of the register at @offset through the DPIO sideband port.
154  */
intel_dpio_reg_write(uint32_t reg,uint32_t val,int phy)155 void intel_dpio_reg_write(uint32_t reg, uint32_t val, int phy)
156 {
157 	if (phy == 0)
158 		vlv_sideband_rw(IOSF_PORT_DPIO, SB_MWR_NP, reg, &val);
159 	else
160 		vlv_sideband_rw(IOSF_PORT_DPIO_2, SB_MWR_NP, reg, &val);
161 }
162 
intel_flisdsi_reg_read(uint32_t reg)163 uint32_t intel_flisdsi_reg_read(uint32_t reg)
164 {
165 	uint32_t val = 0;
166 
167 	vlv_sideband_rw(IOSF_PORT_FLISDSI, SB_CRRDDA_NP, reg, &val);
168 
169 	return val;
170 }
171 
intel_flisdsi_reg_write(uint32_t reg,uint32_t val)172 void intel_flisdsi_reg_write(uint32_t reg, uint32_t val)
173 {
174 	vlv_sideband_rw(IOSF_PORT_FLISDSI, SB_CRWRDA_NP, reg, &val);
175 }
176 
intel_iosf_sb_read(uint32_t port,uint32_t reg)177 uint32_t intel_iosf_sb_read(uint32_t port, uint32_t reg)
178 {
179 	uint32_t val;
180 
181 	vlv_sideband_rw(port, SB_CRRDDA_NP, reg, &val);
182 
183 	return val;
184 }
185 
intel_iosf_sb_write(uint32_t port,uint32_t reg,uint32_t val)186 void intel_iosf_sb_write(uint32_t port, uint32_t reg, uint32_t val)
187 {
188 	vlv_sideband_rw(port, SB_CRWRDA_NP, reg, &val);
189 }
190