1818#include <linux/of_device.h>
1919#include <linux/platform_device.h>
2020
21+ /**
22+ * T602x register interface is cleary different so most of the nemes below are
23+ * probly wrong.
24+ */
25+
26+ #define T602X_FIFO_WR_DPTX_CLK_EN 0x000
27+ #define T602X_FIFO_WR_N_CLK_EN 0x004
28+ #define T602X_FIFO_WR_UNK_EN 0x008
29+ #define T602X_REG_00C 0x00c
30+ #define T602X_REG_014 0x014
31+ #define T602X_REG_018 0x018
32+ #define T602X_REG_01C 0x01c
33+ #define T602X_FIFO_RD_PCLK2_EN 0x024
34+ #define T602X_FIFO_RD_N_CLK_EN 0x028
35+ #define T602X_FIFO_RD_UNK_EN 0x02c
36+ #define T602X_REG_030 0x030
37+ #define T602X_REG_034 0x034
38+
39+ #define T602X_REG_804_STAT 0x804 // status of 0x004
40+ #define T602X_REG_810_STAT 0x810 // status of 0x014
41+ #define T602X_REG_81C_STAT 0x81c // status of 0x024
42+
43+ /**
44+ * T8013, T600x, T8112 dp crossbar registers.
45+ */
46+
2147#define FIFO_WR_DPTX_CLK_EN 0x000
2248#define FIFO_WR_N_CLK_EN 0x004
2349#define FIFO_WR_UNK_EN 0x008
@@ -63,6 +89,7 @@ static const char *apple_dpxbar_names[MUX_MAX] = { "dpphy", "dpin0", "dpin1" };
6389struct apple_dpxbar_hw {
6490 unsigned int n_ufp ;
6591 u32 tunable ;
92+ const struct mux_control_ops * ops ;
6693};
6794
6895struct apple_dpxbar {
@@ -91,6 +118,112 @@ static inline void dpxbar_clear32(struct apple_dpxbar *xbar, u32 reg, u32 clear)
91118 dpxbar_mask32 (xbar , reg , clear , 0 );
92119}
93120
121+ static int apple_dpxbar_set_t602x (struct mux_control * mux , int state )
122+ {
123+ struct apple_dpxbar * dpxbar = mux_chip_priv (mux -> chip );
124+ unsigned int index = mux_control_get_index (mux );
125+ unsigned long flags ;
126+ unsigned int mux_state ;
127+ unsigned int dispext_bit ;
128+ unsigned int dispext_bit_en ;
129+ unsigned int dispext_bit_4 ;
130+ bool enable ;
131+ int ret = 0 ;
132+
133+ if (state == MUX_IDLE_DISCONNECT ) {
134+ /*
135+ * Technically this will select dispext0,0 in the mux control
136+ * register. Practically that doesn't matter since everything
137+ * else is disabled.
138+ */
139+ mux_state = 0 ;
140+ enable = false;
141+ } else if (state >= 0 && state < 9 ) {
142+ dispext_bit = 1 << state ;
143+ dispext_bit_en = 1 << (2 * state );
144+ dispext_bit_4 = 1 << (4 * state );
145+ mux_state = state ;
146+ enable = true;
147+ } else {
148+ return - EINVAL ;
149+ }
150+
151+ spin_lock_irqsave (& dpxbar -> lock , flags );
152+
153+ /* ensure the selected dispext isn't already used in this crossbar */
154+ if (enable ) {
155+ for (int i = 0 ; i < MUX_MAX ; ++ i ) {
156+ if (i == index )
157+ continue ;
158+ if (dpxbar -> selected_dispext [i ] == state ) {
159+ spin_unlock_irqrestore (& dpxbar -> lock , flags );
160+ return - EBUSY ;
161+ }
162+ }
163+ }
164+
165+ if (dpxbar -> selected_dispext [index ] >= 0 ) {
166+ u32 prev_dispext_bit = 1 << dpxbar -> selected_dispext [index ];
167+ u32 prev_dispext_bit_en = 1 << (2 * dpxbar -> selected_dispext [index ]);
168+ u32 prev_dispext_bit_4 = 1 << (4 * dpxbar -> selected_dispext [index ]);
169+
170+ dpxbar_clear32 (dpxbar , T602X_FIFO_RD_UNK_EN , prev_dispext_bit_en );
171+ dpxbar_clear32 (dpxbar , T602X_FIFO_WR_DPTX_CLK_EN , prev_dispext_bit );
172+ dpxbar_clear32 (dpxbar , T602X_REG_00C , prev_dispext_bit_en );
173+
174+ dpxbar_clear32 (dpxbar , T602X_REG_01C , 0x100 );
175+
176+ dpxbar_clear32 (dpxbar , T602X_FIFO_WR_UNK_EN , prev_dispext_bit_en );
177+ dpxbar_clear32 (dpxbar , T602X_REG_018 , prev_dispext_bit_4 );
178+
179+ dpxbar_clear32 (dpxbar , T602X_FIFO_RD_N_CLK_EN , 0x100 );
180+
181+ dpxbar_set32 (dpxbar , T602X_FIFO_WR_N_CLK_EN , prev_dispext_bit_en );
182+ dpxbar_set32 (dpxbar , T602X_REG_014 , prev_dispext_bit_en );
183+
184+ dpxbar_set32 (dpxbar , FIFO_RD_PCLK1_EN , 0x100 );
185+
186+ dpxbar -> selected_dispext [index ] = -1 ;
187+ }
188+
189+ if (enable ) {
190+ dpxbar_set32 (dpxbar , T602X_REG_030 , state << 20 );
191+ dpxbar_set32 (dpxbar , T602X_REG_030 , state << 8 );
192+ udelay (10 );
193+
194+ dpxbar_clear32 (dpxbar , T602X_FIFO_WR_N_CLK_EN , dispext_bit );
195+ dpxbar_clear32 (dpxbar , T602X_REG_014 , dispext_bit_en );
196+
197+ dpxbar_clear32 (dpxbar , T602X_FIFO_RD_PCLK2_EN , 0x100 );
198+
199+ dpxbar_set32 (dpxbar , T602X_FIFO_WR_UNK_EN , dispext_bit );
200+ dpxbar_set32 (dpxbar , T602X_REG_018 , dispext_bit_4 );
201+
202+ dpxbar_set32 (dpxbar , T602X_FIFO_RD_N_CLK_EN , 0x100 );
203+ dpxbar_set32 (dpxbar , T602X_FIFO_WR_DPTX_CLK_EN , dispext_bit );
204+ dpxbar_set32 (dpxbar , T602X_REG_00C , dispext_bit_en );
205+
206+ dpxbar_set32 (dpxbar , T602X_REG_01C , 0x100 );
207+ dpxbar_set32 (dpxbar , T602X_REG_034 , 0x100 );
208+
209+ dpxbar_set32 (dpxbar , T602X_FIFO_RD_UNK_EN , dispext_bit_en );
210+
211+ dpxbar -> selected_dispext [index ] = state ;
212+ }
213+
214+ spin_unlock_irqrestore (& dpxbar -> lock , flags );
215+
216+ if (enable )
217+ dev_err (dpxbar -> dev , "Switched %s to dispext%u,%u\n" ,
218+ apple_dpxbar_names [index ], mux_state >> 1 ,
219+ mux_state & 1 );
220+ else
221+ dev_err (dpxbar -> dev , "Switched %s to disconnected state\n" ,
222+ apple_dpxbar_names [index ]);
223+
224+ return ret ;
225+ }
226+
94227static int apple_dpxbar_set (struct mux_control * mux , int state )
95228{
96229 struct apple_dpxbar * dpxbar = mux_chip_priv (mux -> chip );
@@ -230,6 +363,10 @@ static const struct mux_control_ops apple_dpxbar_ops = {
230363 .set = apple_dpxbar_set ,
231364};
232365
366+ static const struct mux_control_ops apple_dpxbar_t602x_ops = {
367+ .set = apple_dpxbar_set_t602x ,
368+ };
369+
233370static int apple_dpxbar_probe (struct platform_device * pdev )
234371{
235372 struct device * dev = & pdev -> dev ;
@@ -244,17 +381,19 @@ static int apple_dpxbar_probe(struct platform_device *pdev)
244381 return PTR_ERR (mux_chip );
245382
246383 dpxbar = mux_chip_priv (mux_chip );
247- mux_chip -> ops = & apple_dpxbar_ops ;
384+ mux_chip -> ops = hw -> ops ;
248385 spin_lock_init (& dpxbar -> lock );
249386
250387 dpxbar -> dev = dev ;
251388 dpxbar -> regs = devm_platform_ioremap_resource (pdev , 0 );
252389 if (IS_ERR (dpxbar -> regs ))
253390 return PTR_ERR (dpxbar -> regs );
254391
255- readl (dpxbar -> regs + UNK_TUNABLE );
256- writel (hw -> tunable , dpxbar -> regs + UNK_TUNABLE );
257- readl (dpxbar -> regs + UNK_TUNABLE );
392+ if (!of_device_is_compatible (dev -> of_node , "apple,t6020-display-crossbar" )) {
393+ readl (dpxbar -> regs + UNK_TUNABLE );
394+ writel (hw -> tunable , dpxbar -> regs + UNK_TUNABLE );
395+ readl (dpxbar -> regs + UNK_TUNABLE );
396+ }
258397
259398 for (unsigned int i = 0 ; i < MUX_MAX ; ++ i ) {
260399 mux_chip -> mux [i ].states = hw -> n_ufp ;
@@ -272,16 +411,24 @@ static int apple_dpxbar_probe(struct platform_device *pdev)
272411const static struct apple_dpxbar_hw apple_dpxbar_hw_t8103 = {
273412 .n_ufp = 2 ,
274413 .tunable = 0 ,
414+ .ops = & apple_dpxbar_ops ,
275415};
276416
277417const static struct apple_dpxbar_hw apple_dpxbar_hw_t8112 = {
278418 .n_ufp = 4 ,
279419 .tunable = 4278196325 ,
420+ .ops = & apple_dpxbar_ops ,
280421};
281422
282423const static struct apple_dpxbar_hw apple_dpxbar_hw_t6000 = {
283424 .n_ufp = 9 ,
284425 .tunable = 5 ,
426+ .ops = & apple_dpxbar_ops ,
427+ };
428+
429+ const static struct apple_dpxbar_hw apple_dpxbar_hw_t6020 = {
430+ .n_ufp = 9 ,
431+ .ops = & apple_dpxbar_t602x_ops ,
285432};
286433
287434static const struct of_device_id apple_dpxbar_ids [] = {
@@ -297,6 +444,10 @@ static const struct of_device_id apple_dpxbar_ids[] = {
297444 .compatible = "apple,t6000-display-crossbar" ,
298445 .data = & apple_dpxbar_hw_t6000 ,
299446 },
447+ {
448+ .compatible = "apple,t6020-display-crossbar" ,
449+ .data = & apple_dpxbar_hw_t6020 ,
450+ },
300451 {}
301452};
302453MODULE_DEVICE_TABLE (of , apple_dpxbar_ids );
0 commit comments