0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "tb.h"
0010
0011
0012
0013
0014
0015
0016 int tb_lc_read_uuid(struct tb_switch *sw, u32 *uuid)
0017 {
0018 if (!sw->cap_lc)
0019 return -EINVAL;
0020 return tb_sw_read(sw, uuid, TB_CFG_SWITCH, sw->cap_lc + TB_LC_FUSE, 4);
0021 }
0022
0023 static int read_lc_desc(struct tb_switch *sw, u32 *desc)
0024 {
0025 if (!sw->cap_lc)
0026 return -EINVAL;
0027 return tb_sw_read(sw, desc, TB_CFG_SWITCH, sw->cap_lc + TB_LC_DESC, 1);
0028 }
0029
0030 static int find_port_lc_cap(struct tb_port *port)
0031 {
0032 struct tb_switch *sw = port->sw;
0033 int start, phys, ret, size;
0034 u32 desc;
0035
0036 ret = read_lc_desc(sw, &desc);
0037 if (ret)
0038 return ret;
0039
0040
0041 start = (desc & TB_LC_DESC_SIZE_MASK) >> TB_LC_DESC_SIZE_SHIFT;
0042 size = (desc & TB_LC_DESC_PORT_SIZE_MASK) >> TB_LC_DESC_PORT_SIZE_SHIFT;
0043 phys = tb_phy_port_from_link(port->port);
0044
0045 return sw->cap_lc + start + phys * size;
0046 }
0047
0048 static int tb_lc_set_port_configured(struct tb_port *port, bool configured)
0049 {
0050 bool upstream = tb_is_upstream_port(port);
0051 struct tb_switch *sw = port->sw;
0052 u32 ctrl, lane;
0053 int cap, ret;
0054
0055 if (sw->generation < 2)
0056 return 0;
0057
0058 cap = find_port_lc_cap(port);
0059 if (cap < 0)
0060 return cap;
0061
0062 ret = tb_sw_read(sw, &ctrl, TB_CFG_SWITCH, cap + TB_LC_SX_CTRL, 1);
0063 if (ret)
0064 return ret;
0065
0066
0067 if (port->port % 2)
0068 lane = TB_LC_SX_CTRL_L1C;
0069 else
0070 lane = TB_LC_SX_CTRL_L2C;
0071
0072 if (configured) {
0073 ctrl |= lane;
0074 if (upstream)
0075 ctrl |= TB_LC_SX_CTRL_UPSTREAM;
0076 } else {
0077 ctrl &= ~lane;
0078 if (upstream)
0079 ctrl &= ~TB_LC_SX_CTRL_UPSTREAM;
0080 }
0081
0082 return tb_sw_write(sw, &ctrl, TB_CFG_SWITCH, cap + TB_LC_SX_CTRL, 1);
0083 }
0084
0085
0086
0087
0088
0089
0090
0091 int tb_lc_configure_port(struct tb_port *port)
0092 {
0093 return tb_lc_set_port_configured(port, true);
0094 }
0095
0096
0097
0098
0099
0100
0101
0102 void tb_lc_unconfigure_port(struct tb_port *port)
0103 {
0104 tb_lc_set_port_configured(port, false);
0105 }
0106
0107 static int tb_lc_set_xdomain_configured(struct tb_port *port, bool configure)
0108 {
0109 struct tb_switch *sw = port->sw;
0110 u32 ctrl, lane;
0111 int cap, ret;
0112
0113 if (sw->generation < 2)
0114 return 0;
0115
0116 cap = find_port_lc_cap(port);
0117 if (cap < 0)
0118 return cap;
0119
0120 ret = tb_sw_read(sw, &ctrl, TB_CFG_SWITCH, cap + TB_LC_SX_CTRL, 1);
0121 if (ret)
0122 return ret;
0123
0124
0125 if (port->port % 2)
0126 lane = TB_LC_SX_CTRL_L1D;
0127 else
0128 lane = TB_LC_SX_CTRL_L2D;
0129
0130 if (configure)
0131 ctrl |= lane;
0132 else
0133 ctrl &= ~lane;
0134
0135 return tb_sw_write(sw, &ctrl, TB_CFG_SWITCH, cap + TB_LC_SX_CTRL, 1);
0136 }
0137
0138
0139
0140
0141
0142
0143
0144
0145 int tb_lc_configure_xdomain(struct tb_port *port)
0146 {
0147 return tb_lc_set_xdomain_configured(port, true);
0148 }
0149
0150
0151
0152
0153
0154
0155
0156 void tb_lc_unconfigure_xdomain(struct tb_port *port)
0157 {
0158 tb_lc_set_xdomain_configured(port, false);
0159 }
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171 int tb_lc_start_lane_initialization(struct tb_port *port)
0172 {
0173 struct tb_switch *sw = port->sw;
0174 int ret, cap;
0175 u32 ctrl;
0176
0177 if (!tb_route(sw))
0178 return 0;
0179
0180 if (sw->generation < 2)
0181 return 0;
0182
0183 cap = find_port_lc_cap(port);
0184 if (cap < 0)
0185 return cap;
0186
0187 ret = tb_sw_read(sw, &ctrl, TB_CFG_SWITCH, cap + TB_LC_SX_CTRL, 1);
0188 if (ret)
0189 return ret;
0190
0191 ctrl |= TB_LC_SX_CTRL_SLI;
0192
0193 return tb_sw_write(sw, &ctrl, TB_CFG_SWITCH, cap + TB_LC_SX_CTRL, 1);
0194 }
0195
0196
0197
0198
0199
0200
0201
0202
0203 bool tb_lc_is_clx_supported(struct tb_port *port)
0204 {
0205 struct tb_switch *sw = port->sw;
0206 int cap, ret;
0207 u32 val;
0208
0209 cap = find_port_lc_cap(port);
0210 if (cap < 0)
0211 return false;
0212
0213 ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, cap + TB_LC_LINK_ATTR, 1);
0214 if (ret)
0215 return false;
0216
0217 return !!(val & TB_LC_LINK_ATTR_CPS);
0218 }
0219
0220
0221
0222
0223
0224
0225
0226 bool tb_lc_is_usb_plugged(struct tb_port *port)
0227 {
0228 struct tb_switch *sw = port->sw;
0229 int cap, ret;
0230 u32 val;
0231
0232 if (sw->generation != 3)
0233 return false;
0234
0235 cap = find_port_lc_cap(port);
0236 if (cap < 0)
0237 return false;
0238
0239 ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, cap + TB_LC_CS_42, 1);
0240 if (ret)
0241 return false;
0242
0243 return !!(val & TB_LC_CS_42_USB_PLUGGED);
0244 }
0245
0246
0247
0248
0249
0250
0251
0252 bool tb_lc_is_xhci_connected(struct tb_port *port)
0253 {
0254 struct tb_switch *sw = port->sw;
0255 int cap, ret;
0256 u32 val;
0257
0258 if (sw->generation != 3)
0259 return false;
0260
0261 cap = find_port_lc_cap(port);
0262 if (cap < 0)
0263 return false;
0264
0265 ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, cap + TB_LC_LINK_REQ, 1);
0266 if (ret)
0267 return false;
0268
0269 return !!(val & TB_LC_LINK_REQ_XHCI_CONNECT);
0270 }
0271
0272 static int __tb_lc_xhci_connect(struct tb_port *port, bool connect)
0273 {
0274 struct tb_switch *sw = port->sw;
0275 int cap, ret;
0276 u32 val;
0277
0278 if (sw->generation != 3)
0279 return -EINVAL;
0280
0281 cap = find_port_lc_cap(port);
0282 if (cap < 0)
0283 return cap;
0284
0285 ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, cap + TB_LC_LINK_REQ, 1);
0286 if (ret)
0287 return ret;
0288
0289 if (connect)
0290 val |= TB_LC_LINK_REQ_XHCI_CONNECT;
0291 else
0292 val &= ~TB_LC_LINK_REQ_XHCI_CONNECT;
0293
0294 return tb_sw_write(sw, &val, TB_CFG_SWITCH, cap + TB_LC_LINK_REQ, 1);
0295 }
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305 int tb_lc_xhci_connect(struct tb_port *port)
0306 {
0307 int ret;
0308
0309 ret = __tb_lc_xhci_connect(port, true);
0310 if (ret)
0311 return ret;
0312
0313 tb_port_dbg(port, "xHCI connected\n");
0314 return 0;
0315 }
0316
0317
0318
0319
0320
0321
0322
0323
0324 void tb_lc_xhci_disconnect(struct tb_port *port)
0325 {
0326 __tb_lc_xhci_connect(port, false);
0327 tb_port_dbg(port, "xHCI disconnected\n");
0328 }
0329
0330 static int tb_lc_set_wake_one(struct tb_switch *sw, unsigned int offset,
0331 unsigned int flags)
0332 {
0333 u32 ctrl;
0334 int ret;
0335
0336
0337
0338
0339
0340 ret = tb_sw_read(sw, &ctrl, TB_CFG_SWITCH,
0341 offset + TB_LC_SX_CTRL, 1);
0342 if (ret)
0343 return ret;
0344
0345 ctrl &= ~(TB_LC_SX_CTRL_WOC | TB_LC_SX_CTRL_WOD | TB_LC_SX_CTRL_WODPC |
0346 TB_LC_SX_CTRL_WODPD | TB_LC_SX_CTRL_WOP | TB_LC_SX_CTRL_WOU4);
0347
0348 if (flags & TB_WAKE_ON_CONNECT)
0349 ctrl |= TB_LC_SX_CTRL_WOC | TB_LC_SX_CTRL_WOD;
0350 if (flags & TB_WAKE_ON_USB4)
0351 ctrl |= TB_LC_SX_CTRL_WOU4;
0352 if (flags & TB_WAKE_ON_PCIE)
0353 ctrl |= TB_LC_SX_CTRL_WOP;
0354 if (flags & TB_WAKE_ON_DP)
0355 ctrl |= TB_LC_SX_CTRL_WODPC | TB_LC_SX_CTRL_WODPD;
0356
0357 return tb_sw_write(sw, &ctrl, TB_CFG_SWITCH, offset + TB_LC_SX_CTRL, 1);
0358 }
0359
0360
0361
0362
0363
0364
0365
0366
0367 int tb_lc_set_wake(struct tb_switch *sw, unsigned int flags)
0368 {
0369 int start, size, nlc, ret, i;
0370 u32 desc;
0371
0372 if (sw->generation < 2)
0373 return 0;
0374
0375 if (!tb_route(sw))
0376 return 0;
0377
0378 ret = read_lc_desc(sw, &desc);
0379 if (ret)
0380 return ret;
0381
0382
0383 nlc = desc & TB_LC_DESC_NLC_MASK;
0384 start = (desc & TB_LC_DESC_SIZE_MASK) >> TB_LC_DESC_SIZE_SHIFT;
0385 size = (desc & TB_LC_DESC_PORT_SIZE_MASK) >> TB_LC_DESC_PORT_SIZE_SHIFT;
0386
0387
0388 for (i = 0; i < nlc; i++) {
0389 unsigned int offset = sw->cap_lc + start + i * size;
0390
0391 ret = tb_lc_set_wake_one(sw, offset, flags);
0392 if (ret)
0393 return ret;
0394 }
0395
0396 return 0;
0397 }
0398
0399
0400
0401
0402
0403
0404
0405
0406 int tb_lc_set_sleep(struct tb_switch *sw)
0407 {
0408 int start, size, nlc, ret, i;
0409 u32 desc;
0410
0411 if (sw->generation < 2)
0412 return 0;
0413
0414 ret = read_lc_desc(sw, &desc);
0415 if (ret)
0416 return ret;
0417
0418
0419 nlc = desc & TB_LC_DESC_NLC_MASK;
0420 start = (desc & TB_LC_DESC_SIZE_MASK) >> TB_LC_DESC_SIZE_SHIFT;
0421 size = (desc & TB_LC_DESC_PORT_SIZE_MASK) >> TB_LC_DESC_PORT_SIZE_SHIFT;
0422
0423
0424 for (i = 0; i < nlc; i++) {
0425 unsigned int offset = sw->cap_lc + start + i * size;
0426 u32 ctrl;
0427
0428 ret = tb_sw_read(sw, &ctrl, TB_CFG_SWITCH,
0429 offset + TB_LC_SX_CTRL, 1);
0430 if (ret)
0431 return ret;
0432
0433 ctrl |= TB_LC_SX_CTRL_SLP;
0434 ret = tb_sw_write(sw, &ctrl, TB_CFG_SWITCH,
0435 offset + TB_LC_SX_CTRL, 1);
0436 if (ret)
0437 return ret;
0438 }
0439
0440 return 0;
0441 }
0442
0443
0444
0445
0446
0447
0448
0449
0450 bool tb_lc_lane_bonding_possible(struct tb_switch *sw)
0451 {
0452 struct tb_port *up;
0453 int cap, ret;
0454 u32 val;
0455
0456 if (sw->generation < 2)
0457 return false;
0458
0459 up = tb_upstream_port(sw);
0460 cap = find_port_lc_cap(up);
0461 if (cap < 0)
0462 return false;
0463
0464 ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, cap + TB_LC_PORT_ATTR, 1);
0465 if (ret)
0466 return false;
0467
0468 return !!(val & TB_LC_PORT_ATTR_BE);
0469 }
0470
0471 static int tb_lc_dp_sink_from_port(const struct tb_switch *sw,
0472 struct tb_port *in)
0473 {
0474 struct tb_port *port;
0475
0476
0477 tb_switch_for_each_port(sw, port) {
0478 if (tb_port_is_dpin(port))
0479 return in != port;
0480 }
0481
0482 return -EINVAL;
0483 }
0484
0485 static int tb_lc_dp_sink_available(struct tb_switch *sw, int sink)
0486 {
0487 u32 val, alloc;
0488 int ret;
0489
0490 ret = tb_sw_read(sw, &val, TB_CFG_SWITCH,
0491 sw->cap_lc + TB_LC_SNK_ALLOCATION, 1);
0492 if (ret)
0493 return ret;
0494
0495
0496
0497
0498
0499 if (!sink) {
0500 alloc = val & TB_LC_SNK_ALLOCATION_SNK0_MASK;
0501 if (!alloc || alloc == TB_LC_SNK_ALLOCATION_SNK0_CM)
0502 return 0;
0503 } else {
0504 alloc = (val & TB_LC_SNK_ALLOCATION_SNK1_MASK) >>
0505 TB_LC_SNK_ALLOCATION_SNK1_SHIFT;
0506 if (!alloc || alloc == TB_LC_SNK_ALLOCATION_SNK1_CM)
0507 return 0;
0508 }
0509
0510 return -EBUSY;
0511 }
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521 bool tb_lc_dp_sink_query(struct tb_switch *sw, struct tb_port *in)
0522 {
0523 int sink;
0524
0525
0526
0527
0528
0529 if (sw->generation < 3)
0530 return true;
0531
0532 sink = tb_lc_dp_sink_from_port(sw, in);
0533 if (sink < 0)
0534 return false;
0535
0536 return !tb_lc_dp_sink_available(sw, sink);
0537 }
0538
0539
0540
0541
0542
0543
0544
0545
0546
0547
0548
0549 int tb_lc_dp_sink_alloc(struct tb_switch *sw, struct tb_port *in)
0550 {
0551 int ret, sink;
0552 u32 val;
0553
0554 if (sw->generation < 3)
0555 return 0;
0556
0557 sink = tb_lc_dp_sink_from_port(sw, in);
0558 if (sink < 0)
0559 return sink;
0560
0561 ret = tb_lc_dp_sink_available(sw, sink);
0562 if (ret)
0563 return ret;
0564
0565 ret = tb_sw_read(sw, &val, TB_CFG_SWITCH,
0566 sw->cap_lc + TB_LC_SNK_ALLOCATION, 1);
0567 if (ret)
0568 return ret;
0569
0570 if (!sink) {
0571 val &= ~TB_LC_SNK_ALLOCATION_SNK0_MASK;
0572 val |= TB_LC_SNK_ALLOCATION_SNK0_CM;
0573 } else {
0574 val &= ~TB_LC_SNK_ALLOCATION_SNK1_MASK;
0575 val |= TB_LC_SNK_ALLOCATION_SNK1_CM <<
0576 TB_LC_SNK_ALLOCATION_SNK1_SHIFT;
0577 }
0578
0579 ret = tb_sw_write(sw, &val, TB_CFG_SWITCH,
0580 sw->cap_lc + TB_LC_SNK_ALLOCATION, 1);
0581
0582 if (ret)
0583 return ret;
0584
0585 tb_port_dbg(in, "sink %d allocated\n", sink);
0586 return 0;
0587 }
0588
0589
0590
0591
0592
0593
0594
0595
0596 int tb_lc_dp_sink_dealloc(struct tb_switch *sw, struct tb_port *in)
0597 {
0598 int ret, sink;
0599 u32 val;
0600
0601 if (sw->generation < 3)
0602 return 0;
0603
0604 sink = tb_lc_dp_sink_from_port(sw, in);
0605 if (sink < 0)
0606 return sink;
0607
0608
0609 ret = tb_lc_dp_sink_available(sw, sink);
0610 if (ret)
0611 return ret;
0612
0613 ret = tb_sw_read(sw, &val, TB_CFG_SWITCH,
0614 sw->cap_lc + TB_LC_SNK_ALLOCATION, 1);
0615 if (ret)
0616 return ret;
0617
0618 if (!sink)
0619 val &= ~TB_LC_SNK_ALLOCATION_SNK0_MASK;
0620 else
0621 val &= ~TB_LC_SNK_ALLOCATION_SNK1_MASK;
0622
0623 ret = tb_sw_write(sw, &val, TB_CFG_SWITCH,
0624 sw->cap_lc + TB_LC_SNK_ALLOCATION, 1);
0625 if (ret)
0626 return ret;
0627
0628 tb_port_dbg(in, "sink %d de-allocated\n", sink);
0629 return 0;
0630 }
0631
0632
0633
0634
0635
0636
0637
0638
0639 int tb_lc_force_power(struct tb_switch *sw)
0640 {
0641 u32 in = 0xffff;
0642
0643 return tb_sw_write(sw, &in, TB_CFG_SWITCH, TB_LC_POWER, 1);
0644 }