Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: typec: intel_pmc_mux: Check the port status before connect

The PMC microcontroller that we use for configuration, does
not supply any status information back. For port status we
need to talk to another controller on the board called IOM
(I/O manager).

By checking the port status before configuring the muxes, we
can make sure that we do not reconfigure the port after
bootup when the system firmware (for example BIOS) has
already configured it.

Using the status information also to check if DisplayPort
HPD is still asserted when the cable plug is disconnected,
and clearing it if it is.

Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: Rajmohan Mani <rajmohan.mani@intel.com>
Reviewed-by: Utkarsh Patel <utkarsh.h.patel@intel.com>
Tested-by: Utkarsh Patel <utkarsh.h.patel@intel.com>
Link: https://lore.kernel.org/r/20200907142428.35838-2-heikki.krogerus@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Heikki Krogerus and committed by
Greg Kroah-Hartman
43d596e3 5df7ef7d

+141 -11
+141 -11
drivers/usb/typec/mux/intel_pmc_mux.c
··· 83 83 #define PMC_USB_DP_HPD_LVL BIT(4) 84 84 #define PMC_USB_DP_HPD_IRQ BIT(5) 85 85 86 + /* 87 + * Input Output Manager (IOM) PORT STATUS 88 + */ 89 + #define IOM_PORT_STATUS_OFFSET 0x560 90 + 91 + #define IOM_PORT_STATUS_ACTIVITY_TYPE_MASK GENMASK(9, 6) 92 + #define IOM_PORT_STATUS_ACTIVITY_TYPE_SHIFT 6 93 + #define IOM_PORT_STATUS_ACTIVITY_TYPE_USB 0x03 94 + /* activity type: Safe Mode */ 95 + #define IOM_PORT_STATUS_ACTIVITY_TYPE_SAFE_MODE 0x04 96 + /* activity type: Display Port */ 97 + #define IOM_PORT_STATUS_ACTIVITY_TYPE_DP 0x05 98 + /* activity type: Display Port Multi Function Device */ 99 + #define IOM_PORT_STATUS_ACTIVITY_TYPE_DP_MFD 0x06 100 + /* activity type: Thunderbolt */ 101 + #define IOM_PORT_STATUS_ACTIVITY_TYPE_TBT 0x07 102 + #define IOM_PORT_STATUS_ACTIVITY_TYPE_ALT_MODE_USB 0x0c 103 + #define IOM_PORT_STATUS_ACTIVITY_TYPE_ALT_MODE_TBT_USB 0x0d 104 + /* Upstream Facing Port Information */ 105 + #define IOM_PORT_STATUS_UFP BIT(10) 106 + /* Display Port Hot Plug Detect status */ 107 + #define IOM_PORT_STATUS_DHPD_HPD_STATUS_MASK GENMASK(13, 12) 108 + #define IOM_PORT_STATUS_DHPD_HPD_STATUS_SHIFT 12 109 + #define IOM_PORT_STATUS_DHPD_HPD_STATUS_ASSERT 0x01 110 + #define IOM_PORT_STATUS_DHPD_HPD_SOURCE_TBT BIT(14) 111 + #define IOM_PORT_STATUS_CONNECTED BIT(31) 112 + 113 + #define IOM_PORT_ACTIVITY_IS(_status_, _type_) \ 114 + ((((_status_) & IOM_PORT_STATUS_ACTIVITY_TYPE_MASK) >> \ 115 + IOM_PORT_STATUS_ACTIVITY_TYPE_SHIFT) == \ 116 + (IOM_PORT_STATUS_ACTIVITY_TYPE_##_type_)) 117 + 118 + #define IOM_PORT_HPD_ASSERTED(_status_) \ 119 + ((((_status_) & IOM_PORT_STATUS_DHPD_HPD_STATUS_MASK) >> \ 120 + IOM_PORT_STATUS_DHPD_HPD_STATUS_SHIFT) & \ 121 + IOM_PORT_STATUS_DHPD_HPD_STATUS_ASSERT) 122 + 86 123 struct pmc_usb; 87 124 88 125 struct pmc_usb_port { 89 126 int num; 127 + u32 iom_status; 90 128 struct pmc_usb *pmc; 91 129 struct typec_mux *typec_mux; 92 130 struct typec_switch *typec_sw; ··· 145 107 struct device *dev; 146 108 struct intel_scu_ipc_dev *ipc; 147 109 struct pmc_usb_port *port; 110 + struct acpi_device *iom_adev; 111 + void __iomem *iom_base; 148 112 }; 113 + 114 + static void update_port_status(struct pmc_usb_port *port) 115 + { 116 + port->iom_status = readl(port->pmc->iom_base + IOM_PORT_STATUS_OFFSET + 117 + port->usb3_port * sizeof(u32)); 118 + } 149 119 150 120 static int sbu_orientation(struct pmc_usb_port *port) 151 121 { ··· 191 145 } 192 146 193 147 static int 194 - pmc_usb_mux_dp_hpd(struct pmc_usb_port *port, struct typec_mux_state *state) 148 + pmc_usb_mux_dp_hpd(struct pmc_usb_port *port, struct typec_displayport_data *dp) 195 149 { 196 - struct typec_displayport_data *data = state->data; 197 150 u8 msg[2] = { }; 198 151 199 152 msg[0] = PMC_USB_DP_HPD; 200 153 msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; 201 154 202 - if (data->status & DP_STATUS_IRQ_HPD) 155 + if (dp->status & DP_STATUS_IRQ_HPD) 203 156 msg[1] = PMC_USB_DP_HPD_IRQ; 204 157 205 - if (data->status & DP_STATUS_HPD_STATE) 158 + if (dp->status & DP_STATUS_HPD_STATE) 206 159 msg[1] |= PMC_USB_DP_HPD_LVL; 207 160 208 161 return pmc_usb_command(port, msg, sizeof(msg)); ··· 214 169 struct altmode_req req = { }; 215 170 int ret; 216 171 172 + if (IOM_PORT_ACTIVITY_IS(port->iom_status, DP) || 173 + IOM_PORT_ACTIVITY_IS(port->iom_status, DP_MFD)) { 174 + if (IOM_PORT_HPD_ASSERTED(port->iom_status) && 175 + (!(data->status & DP_STATUS_IRQ_HPD) && 176 + data->status & DP_STATUS_HPD_STATE)) 177 + return 0; 178 + 179 + return pmc_usb_mux_dp_hpd(port, state->data); 180 + } 181 + 217 182 if (data->status & DP_STATUS_IRQ_HPD) 218 - return pmc_usb_mux_dp_hpd(port, state); 183 + return pmc_usb_mux_dp_hpd(port, state->data); 219 184 220 185 req.usage = PMC_USB_ALT_MODE; 221 186 req.usage |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; ··· 247 192 if (ret) 248 193 return ret; 249 194 250 - if (data->status & DP_STATUS_HPD_STATE) 251 - return pmc_usb_mux_dp_hpd(port, state); 195 + if (data->status & (DP_STATUS_IRQ_HPD | DP_STATUS_HPD_STATE)) 196 + return pmc_usb_mux_dp_hpd(port, state->data); 252 197 253 198 return 0; 254 199 } ··· 259 204 struct typec_thunderbolt_data *data = state->data; 260 205 u8 cable_speed = TBT_CABLE_SPEED(data->cable_mode); 261 206 struct altmode_req req = { }; 207 + 208 + if (IOM_PORT_ACTIVITY_IS(port->iom_status, TBT) || 209 + IOM_PORT_ACTIVITY_IS(port->iom_status, ALT_MODE_TBT_USB)) 210 + return 0; 262 211 263 212 req.usage = PMC_USB_ALT_MODE; 264 213 req.usage |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; ··· 298 239 struct altmode_req req = { }; 299 240 u8 cable_speed; 300 241 242 + if (IOM_PORT_ACTIVITY_IS(port->iom_status, TBT) || 243 + IOM_PORT_ACTIVITY_IS(port->iom_status, ALT_MODE_TBT_USB)) 244 + return 0; 245 + 301 246 req.usage = PMC_USB_ALT_MODE; 302 247 req.usage |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; 303 248 req.mode_type = PMC_USB_MODE_TYPE_TBT << PMC_USB_MODE_TYPE_SHIFT; ··· 336 273 { 337 274 u8 msg; 338 275 276 + if (IOM_PORT_ACTIVITY_IS(port->iom_status, SAFE_MODE)) 277 + return 0; 278 + 339 279 msg = PMC_USB_SAFE_MODE; 340 280 msg |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; 341 281 ··· 348 282 static int pmc_usb_connect(struct pmc_usb_port *port) 349 283 { 350 284 u8 msg[2]; 285 + 286 + if (port->iom_status & IOM_PORT_STATUS_CONNECTED) 287 + return 0; 351 288 352 289 msg[0] = PMC_USB_CONNECT; 353 290 msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; ··· 364 295 365 296 static int pmc_usb_disconnect(struct pmc_usb_port *port) 366 297 { 298 + struct typec_displayport_data data = { }; 367 299 u8 msg[2]; 300 + 301 + if (!(port->iom_status & IOM_PORT_STATUS_CONNECTED)) 302 + return 0; 303 + 304 + /* Clear DisplayPort HPD if it's still asserted. */ 305 + if (IOM_PORT_HPD_ASSERTED(port->iom_status)) 306 + pmc_usb_mux_dp_hpd(port, &data); 368 307 369 308 msg[0] = PMC_USB_DISCONNECT; 370 309 msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; ··· 386 309 pmc_usb_mux_set(struct typec_mux *mux, struct typec_mux_state *state) 387 310 { 388 311 struct pmc_usb_port *port = typec_mux_get_drvdata(mux); 312 + 313 + update_port_status(port); 389 314 390 315 if (port->orientation == TYPEC_ORIENTATION_NONE || port->role == USB_ROLE_NONE) 391 316 return 0; ··· 424 345 { 425 346 struct pmc_usb_port *port = typec_switch_get_drvdata(sw); 426 347 427 - if (port->orientation == orientation) 428 - return 0; 348 + update_port_status(port); 429 349 430 350 port->orientation = orientation; 431 351 ··· 442 364 { 443 365 struct pmc_usb_port *port = usb_role_switch_get_drvdata(sw); 444 366 445 - if (port->role == role) 446 - return 0; 367 + update_port_status(port); 447 368 448 369 port->role = role; 449 370 ··· 527 450 return ret; 528 451 } 529 452 453 + static int is_memory(struct acpi_resource *res, void *data) 454 + { 455 + struct resource r; 456 + 457 + return !acpi_dev_resource_memory(res, &r); 458 + } 459 + 460 + static int pmc_usb_probe_iom(struct pmc_usb *pmc) 461 + { 462 + struct list_head resource_list; 463 + struct resource_entry *rentry; 464 + struct acpi_device *adev; 465 + int ret; 466 + 467 + adev = acpi_dev_get_first_match_dev("INTC1072", NULL, -1); 468 + if (!adev) 469 + return -ENODEV; 470 + 471 + INIT_LIST_HEAD(&resource_list); 472 + ret = acpi_dev_get_resources(adev, &resource_list, is_memory, NULL); 473 + if (ret < 0) 474 + return ret; 475 + 476 + rentry = list_first_entry_or_null(&resource_list, struct resource_entry, node); 477 + if (rentry) 478 + pmc->iom_base = devm_ioremap_resource(pmc->dev, rentry->res); 479 + 480 + acpi_dev_free_resource_list(&resource_list); 481 + 482 + if (!pmc->iom_base) { 483 + put_device(&adev->dev); 484 + return -ENOMEM; 485 + } 486 + 487 + pmc->iom_adev = adev; 488 + 489 + return 0; 490 + } 491 + 530 492 static int pmc_usb_probe(struct platform_device *pdev) 531 493 { 532 494 struct fwnode_handle *fwnode = NULL; ··· 580 464 device_for_each_child_node(&pdev->dev, fwnode) 581 465 pmc->num_ports++; 582 466 467 + /* The IOM microcontroller has a limitation of max 4 ports. */ 468 + if (pmc->num_ports > 4) { 469 + dev_err(&pdev->dev, "driver limited to 4 ports\n"); 470 + return -ERANGE; 471 + } 472 + 583 473 pmc->port = devm_kcalloc(&pdev->dev, pmc->num_ports, 584 474 sizeof(struct pmc_usb_port), GFP_KERNEL); 585 475 if (!pmc->port) ··· 596 474 return -ENODEV; 597 475 598 476 pmc->dev = &pdev->dev; 477 + 478 + ret = pmc_usb_probe_iom(pmc); 479 + if (ret) 480 + return ret; 599 481 600 482 /* 601 483 * For every physical USB connector (USB2 and USB3 combo) there is a ··· 625 499 typec_mux_unregister(pmc->port[i].typec_mux); 626 500 } 627 501 502 + put_device(&pmc->iom_adev->dev); 503 + 628 504 return ret; 629 505 } 630 506 ··· 639 511 typec_switch_unregister(pmc->port[i].typec_sw); 640 512 typec_mux_unregister(pmc->port[i].typec_mux); 641 513 } 514 + 515 + put_device(&pmc->iom_adev->dev); 642 516 643 517 return 0; 644 518 }