Skip to content

Commit 592b582

Browse files
jannaumarcan
authored andcommitted
mux: apple dp crossbar: Support t602x DP cross bar variant
This is a simplified version and probably should live in a separate file. Even the shared registers are quite different. Signed-off-by: Janne Grunau <j@jannau.net>
1 parent fcfa774 commit 592b582

1 file changed

Lines changed: 155 additions & 4 deletions

File tree

drivers/mux/apple-display-crossbar.c

Lines changed: 155 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,32 @@
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" };
6389
struct apple_dpxbar_hw {
6490
unsigned int n_ufp;
6591
u32 tunable;
92+
const struct mux_control_ops *ops;
6693
};
6794

6895
struct 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+
94227
static 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+
233370
static 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)
272411
const static struct apple_dpxbar_hw apple_dpxbar_hw_t8103 = {
273412
.n_ufp = 2,
274413
.tunable = 0,
414+
.ops = &apple_dpxbar_ops,
275415
};
276416

277417
const static struct apple_dpxbar_hw apple_dpxbar_hw_t8112 = {
278418
.n_ufp = 4,
279419
.tunable = 4278196325,
420+
.ops = &apple_dpxbar_ops,
280421
};
281422

282423
const 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

287434
static 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
};
302453
MODULE_DEVICE_TABLE(of, apple_dpxbar_ids);

0 commit comments

Comments
 (0)