552 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.4 * Copyright (c) 2022, Linaro Ltd5 */6#include <linux/auxiliary_bus.h>7#include <linux/bitfield.h>8#include <linux/module.h>9#include <linux/of.h>10#include <linux/of_device.h>11#include <linux/mutex.h>12#include <linux/property.h>13#include <linux/soc/qcom/pdr.h>14#include <drm/bridge/aux-bridge.h>15 16#include <linux/usb/typec_altmode.h>17#include <linux/usb/typec_dp.h>18#include <linux/usb/typec_mux.h>19#include <linux/usb/typec_retimer.h>20 21#include <linux/soc/qcom/pmic_glink.h>22 23#define PMIC_GLINK_MAX_PORTS 324 25#define USBC_SC8180X_NOTIFY_IND 0x1326#define USBC_CMD_WRITE_REQ 0x1527#define USBC_NOTIFY_IND 0x1628 29#define ALTMODE_PAN_EN 0x1030#define ALTMODE_PAN_ACK 0x1131 32struct usbc_write_req {33 struct pmic_glink_hdr hdr;34 __le32 cmd;35 __le32 arg;36 __le32 reserved;37};38 39#define NOTIFY_PAYLOAD_SIZE 1640struct usbc_notify {41 struct pmic_glink_hdr hdr;42 char payload[NOTIFY_PAYLOAD_SIZE];43 u32 reserved;44};45 46struct usbc_sc8180x_notify {47 struct pmic_glink_hdr hdr;48 __le32 notification;49 __le32 reserved[2];50};51 52enum pmic_glink_altmode_pin_assignment {53 DPAM_HPD_OUT,54 DPAM_HPD_A,55 DPAM_HPD_B,56 DPAM_HPD_C,57 DPAM_HPD_D,58 DPAM_HPD_E,59 DPAM_HPD_F,60};61 62struct pmic_glink_altmode;63 64#define work_to_altmode_port(w) container_of((w), struct pmic_glink_altmode_port, work)65 66struct pmic_glink_altmode_port {67 struct pmic_glink_altmode *altmode;68 unsigned int index;69 70 struct typec_switch *typec_switch;71 struct typec_mux *typec_mux;72 struct typec_mux_state state;73 struct typec_retimer *typec_retimer;74 struct typec_retimer_state retimer_state;75 struct typec_altmode dp_alt;76 77 struct work_struct work;78 79 struct auxiliary_device *bridge;80 81 enum typec_orientation orientation;82 u16 svid;83 u8 dp_data;84 u8 mode;85 u8 hpd_state;86 u8 hpd_irq;87};88 89#define work_to_altmode(w) container_of((w), struct pmic_glink_altmode, enable_work)90 91struct pmic_glink_altmode {92 struct device *dev;93 94 unsigned int owner_id;95 96 /* To synchronize WRITE_REQ acks */97 struct mutex lock;98 99 struct completion pan_ack;100 struct pmic_glink_client *client;101 102 struct work_struct enable_work;103 104 struct pmic_glink_altmode_port ports[PMIC_GLINK_MAX_PORTS];105};106 107static int pmic_glink_altmode_request(struct pmic_glink_altmode *altmode, u32 cmd, u32 arg)108{109 struct usbc_write_req req = {};110 unsigned long left;111 int ret;112 113 /*114 * The USBC_CMD_WRITE_REQ ack doesn't identify the request, so wait for115 * one ack at a time.116 */117 mutex_lock(&altmode->lock);118 119 req.hdr.owner = cpu_to_le32(altmode->owner_id);120 req.hdr.type = cpu_to_le32(PMIC_GLINK_REQ_RESP);121 req.hdr.opcode = cpu_to_le32(USBC_CMD_WRITE_REQ);122 req.cmd = cpu_to_le32(cmd);123 req.arg = cpu_to_le32(arg);124 125 ret = pmic_glink_send(altmode->client, &req, sizeof(req));126 if (ret) {127 dev_err(altmode->dev, "failed to send altmode request: %#x (%d)\n", cmd, ret);128 goto out_unlock;129 }130 131 left = wait_for_completion_timeout(&altmode->pan_ack, 5 * HZ);132 if (!left) {133 dev_err(altmode->dev, "timeout waiting for altmode request ack for: %#x\n", cmd);134 ret = -ETIMEDOUT;135 }136 137out_unlock:138 mutex_unlock(&altmode->lock);139 return ret;140}141 142static void pmic_glink_altmode_enable_dp(struct pmic_glink_altmode *altmode,143 struct pmic_glink_altmode_port *port,144 u8 mode, bool hpd_state,145 bool hpd_irq)146{147 struct typec_displayport_data dp_data = {};148 int ret;149 150 dp_data.status = DP_STATUS_ENABLED;151 if (hpd_state)152 dp_data.status |= DP_STATUS_HPD_STATE;153 if (hpd_irq)154 dp_data.status |= DP_STATUS_IRQ_HPD;155 dp_data.conf = DP_CONF_SET_PIN_ASSIGN(mode);156 157 port->state.alt = &port->dp_alt;158 port->state.data = &dp_data;159 port->state.mode = TYPEC_MODAL_STATE(mode);160 161 ret = typec_mux_set(port->typec_mux, &port->state);162 if (ret)163 dev_err(altmode->dev, "failed to switch mux to DP: %d\n", ret);164 165 port->retimer_state.alt = &port->dp_alt;166 port->retimer_state.data = &dp_data;167 port->retimer_state.mode = TYPEC_MODAL_STATE(mode);168 169 ret = typec_retimer_set(port->typec_retimer, &port->retimer_state);170 if (ret)171 dev_err(altmode->dev, "failed to setup retimer to DP: %d\n", ret);172}173 174static void pmic_glink_altmode_enable_usb(struct pmic_glink_altmode *altmode,175 struct pmic_glink_altmode_port *port)176{177 int ret;178 179 port->state.alt = NULL;180 port->state.data = NULL;181 port->state.mode = TYPEC_STATE_USB;182 183 ret = typec_mux_set(port->typec_mux, &port->state);184 if (ret)185 dev_err(altmode->dev, "failed to switch mux to USB: %d\n", ret);186 187 port->retimer_state.alt = NULL;188 port->retimer_state.data = NULL;189 port->retimer_state.mode = TYPEC_STATE_USB;190 191 ret = typec_retimer_set(port->typec_retimer, &port->retimer_state);192 if (ret)193 dev_err(altmode->dev, "failed to setup retimer to USB: %d\n", ret);194}195 196static void pmic_glink_altmode_safe(struct pmic_glink_altmode *altmode,197 struct pmic_glink_altmode_port *port)198{199 int ret;200 201 port->state.alt = NULL;202 port->state.data = NULL;203 port->state.mode = TYPEC_STATE_SAFE;204 205 ret = typec_mux_set(port->typec_mux, &port->state);206 if (ret)207 dev_err(altmode->dev, "failed to switch mux to safe mode: %d\n", ret);208 209 port->retimer_state.alt = NULL;210 port->retimer_state.data = NULL;211 port->retimer_state.mode = TYPEC_STATE_SAFE;212 213 ret = typec_retimer_set(port->typec_retimer, &port->retimer_state);214 if (ret)215 dev_err(altmode->dev, "failed to setup retimer to USB: %d\n", ret);216}217 218static void pmic_glink_altmode_worker(struct work_struct *work)219{220 struct pmic_glink_altmode_port *alt_port = work_to_altmode_port(work);221 struct pmic_glink_altmode *altmode = alt_port->altmode;222 223 typec_switch_set(alt_port->typec_switch, alt_port->orientation);224 225 if (alt_port->svid == USB_TYPEC_DP_SID && alt_port->mode == 0xff)226 pmic_glink_altmode_safe(altmode, alt_port);227 else if (alt_port->svid == USB_TYPEC_DP_SID)228 pmic_glink_altmode_enable_dp(altmode, alt_port, alt_port->mode,229 alt_port->hpd_state, alt_port->hpd_irq);230 else231 pmic_glink_altmode_enable_usb(altmode, alt_port);232 233 drm_aux_hpd_bridge_notify(&alt_port->bridge->dev,234 alt_port->hpd_state ?235 connector_status_connected :236 connector_status_disconnected);237 238 pmic_glink_altmode_request(altmode, ALTMODE_PAN_ACK, alt_port->index);239}240 241static enum typec_orientation pmic_glink_altmode_orientation(unsigned int orientation)242{243 if (orientation == 0)244 return TYPEC_ORIENTATION_NORMAL;245 else if (orientation == 1)246 return TYPEC_ORIENTATION_REVERSE;247 else248 return TYPEC_ORIENTATION_NONE;249}250 251#define SC8180X_PORT_MASK 0x000000ff252#define SC8180X_ORIENTATION_MASK 0x0000ff00253#define SC8180X_MUX_MASK 0x00ff0000254#define SC8180X_MODE_MASK 0x3f000000255#define SC8180X_HPD_STATE_MASK 0x40000000256#define SC8180X_HPD_IRQ_MASK 0x80000000257 258static void pmic_glink_altmode_sc8180xp_notify(struct pmic_glink_altmode *altmode,259 const void *data, size_t len)260{261 struct pmic_glink_altmode_port *alt_port;262 const struct usbc_sc8180x_notify *msg;263 u32 notification;264 u8 orientation;265 u8 hpd_state;266 u8 hpd_irq;267 u16 svid;268 u8 port;269 u8 mode;270 u8 mux;271 272 if (len != sizeof(*msg)) {273 dev_warn(altmode->dev, "invalid length of USBC_NOTIFY indication: %zd\n", len);274 return;275 }276 277 msg = data;278 notification = le32_to_cpu(msg->notification);279 port = FIELD_GET(SC8180X_PORT_MASK, notification);280 orientation = FIELD_GET(SC8180X_ORIENTATION_MASK, notification);281 mux = FIELD_GET(SC8180X_MUX_MASK, notification);282 mode = FIELD_GET(SC8180X_MODE_MASK, notification);283 hpd_state = FIELD_GET(SC8180X_HPD_STATE_MASK, notification);284 hpd_irq = FIELD_GET(SC8180X_HPD_IRQ_MASK, notification);285 286 svid = mux == 2 ? USB_TYPEC_DP_SID : 0;287 288 if (port >= ARRAY_SIZE(altmode->ports) || !altmode->ports[port].altmode) {289 dev_dbg(altmode->dev, "notification on undefined port %d\n", port);290 return;291 }292 293 alt_port = &altmode->ports[port];294 alt_port->orientation = pmic_glink_altmode_orientation(orientation);295 alt_port->svid = svid;296 alt_port->mode = mode;297 alt_port->hpd_state = hpd_state;298 alt_port->hpd_irq = hpd_irq;299 schedule_work(&alt_port->work);300}301 302#define SC8280XP_DPAM_MASK 0x3f303#define SC8280XP_HPD_STATE_MASK BIT(6)304#define SC8280XP_HPD_IRQ_MASK BIT(7)305 306static void pmic_glink_altmode_sc8280xp_notify(struct pmic_glink_altmode *altmode,307 u16 svid, const void *data, size_t len)308{309 struct pmic_glink_altmode_port *alt_port;310 const struct usbc_notify *notify;311 u8 orientation;312 u8 hpd_state;313 u8 hpd_irq;314 u8 mode;315 u8 port;316 317 if (len != sizeof(*notify)) {318 dev_warn(altmode->dev, "invalid length USBC_NOTIFY_IND: %zd\n",319 len);320 return;321 }322 323 notify = data;324 325 port = notify->payload[0];326 orientation = notify->payload[1];327 mode = FIELD_GET(SC8280XP_DPAM_MASK, notify->payload[8]) - DPAM_HPD_A;328 hpd_state = FIELD_GET(SC8280XP_HPD_STATE_MASK, notify->payload[8]);329 hpd_irq = FIELD_GET(SC8280XP_HPD_IRQ_MASK, notify->payload[8]);330 331 if (port >= ARRAY_SIZE(altmode->ports) || !altmode->ports[port].altmode) {332 dev_dbg(altmode->dev, "notification on undefined port %d\n", port);333 return;334 }335 336 alt_port = &altmode->ports[port];337 alt_port->orientation = pmic_glink_altmode_orientation(orientation);338 alt_port->svid = svid;339 alt_port->mode = mode;340 alt_port->hpd_state = hpd_state;341 alt_port->hpd_irq = hpd_irq;342 schedule_work(&alt_port->work);343}344 345static void pmic_glink_altmode_callback(const void *data, size_t len, void *priv)346{347 struct pmic_glink_altmode *altmode = priv;348 const struct pmic_glink_hdr *hdr = data;349 u16 opcode;350 u16 svid;351 352 opcode = le32_to_cpu(hdr->opcode) & 0xff;353 svid = le32_to_cpu(hdr->opcode) >> 16;354 355 switch (opcode) {356 case USBC_CMD_WRITE_REQ:357 complete(&altmode->pan_ack);358 break;359 case USBC_NOTIFY_IND:360 pmic_glink_altmode_sc8280xp_notify(altmode, svid, data, len);361 break;362 case USBC_SC8180X_NOTIFY_IND:363 pmic_glink_altmode_sc8180xp_notify(altmode, data, len);364 break;365 }366}367 368static void pmic_glink_altmode_put_retimer(void *data)369{370 typec_retimer_put(data);371}372 373static void pmic_glink_altmode_put_mux(void *data)374{375 typec_mux_put(data);376}377 378static void pmic_glink_altmode_put_switch(void *data)379{380 typec_switch_put(data);381}382 383static void pmic_glink_altmode_enable_worker(struct work_struct *work)384{385 struct pmic_glink_altmode *altmode = work_to_altmode(work);386 int ret;387 388 ret = pmic_glink_altmode_request(altmode, ALTMODE_PAN_EN, 0);389 if (ret)390 dev_err(altmode->dev, "failed to request altmode notifications: %d\n", ret);391}392 393static void pmic_glink_altmode_pdr_notify(void *priv, int state)394{395 struct pmic_glink_altmode *altmode = priv;396 397 if (state == SERVREG_SERVICE_STATE_UP)398 schedule_work(&altmode->enable_work);399}400 401static const struct of_device_id pmic_glink_altmode_of_quirks[] = {402 { .compatible = "qcom,sc8180x-pmic-glink", .data = (void *)PMIC_GLINK_OWNER_USBC },403 {}404};405 406static int pmic_glink_altmode_probe(struct auxiliary_device *adev,407 const struct auxiliary_device_id *id)408{409 struct pmic_glink_altmode_port *alt_port;410 struct pmic_glink_altmode *altmode;411 const struct of_device_id *match;412 struct fwnode_handle *fwnode;413 struct device *dev = &adev->dev;414 u32 port;415 int ret;416 417 altmode = devm_kzalloc(dev, sizeof(*altmode), GFP_KERNEL);418 if (!altmode)419 return -ENOMEM;420 421 altmode->dev = dev;422 423 match = of_match_device(pmic_glink_altmode_of_quirks, dev->parent);424 if (match)425 altmode->owner_id = (unsigned long)match->data;426 else427 altmode->owner_id = PMIC_GLINK_OWNER_USBC_PAN;428 429 INIT_WORK(&altmode->enable_work, pmic_glink_altmode_enable_worker);430 init_completion(&altmode->pan_ack);431 mutex_init(&altmode->lock);432 433 device_for_each_child_node(dev, fwnode) {434 ret = fwnode_property_read_u32(fwnode, "reg", &port);435 if (ret < 0) {436 dev_err(dev, "missing reg property of %pOFn\n", fwnode);437 fwnode_handle_put(fwnode);438 return ret;439 }440 441 if (port >= ARRAY_SIZE(altmode->ports)) {442 dev_warn(dev, "invalid connector number, ignoring\n");443 continue;444 }445 446 if (altmode->ports[port].altmode) {447 dev_err(dev, "multiple connector definition for port %u\n", port);448 fwnode_handle_put(fwnode);449 return -EINVAL;450 }451 452 alt_port = &altmode->ports[port];453 alt_port->altmode = altmode;454 alt_port->index = port;455 INIT_WORK(&alt_port->work, pmic_glink_altmode_worker);456 457 alt_port->bridge = devm_drm_dp_hpd_bridge_alloc(dev, to_of_node(fwnode));458 if (IS_ERR(alt_port->bridge)) {459 fwnode_handle_put(fwnode);460 return PTR_ERR(alt_port->bridge);461 }462 463 alt_port->dp_alt.svid = USB_TYPEC_DP_SID;464 alt_port->dp_alt.mode = USB_TYPEC_DP_MODE;465 alt_port->dp_alt.active = 1;466 467 alt_port->typec_mux = fwnode_typec_mux_get(fwnode);468 if (IS_ERR(alt_port->typec_mux)) {469 fwnode_handle_put(fwnode);470 return dev_err_probe(dev, PTR_ERR(alt_port->typec_mux),471 "failed to acquire mode-switch for port: %d\n",472 port);473 }474 475 ret = devm_add_action_or_reset(dev, pmic_glink_altmode_put_mux,476 alt_port->typec_mux);477 if (ret) {478 fwnode_handle_put(fwnode);479 return ret;480 }481 482 alt_port->typec_retimer = fwnode_typec_retimer_get(fwnode);483 if (IS_ERR(alt_port->typec_retimer)) {484 fwnode_handle_put(fwnode);485 return dev_err_probe(dev, PTR_ERR(alt_port->typec_retimer),486 "failed to acquire retimer-switch for port: %d\n",487 port);488 }489 490 ret = devm_add_action_or_reset(dev, pmic_glink_altmode_put_retimer,491 alt_port->typec_retimer);492 if (ret) {493 fwnode_handle_put(fwnode);494 return ret;495 }496 497 alt_port->typec_switch = fwnode_typec_switch_get(fwnode);498 if (IS_ERR(alt_port->typec_switch)) {499 fwnode_handle_put(fwnode);500 return dev_err_probe(dev, PTR_ERR(alt_port->typec_switch),501 "failed to acquire orientation-switch for port: %d\n",502 port);503 }504 505 ret = devm_add_action_or_reset(dev, pmic_glink_altmode_put_switch,506 alt_port->typec_switch);507 if (ret) {508 fwnode_handle_put(fwnode);509 return ret;510 }511 }512 513 for (port = 0; port < ARRAY_SIZE(altmode->ports); port++) {514 alt_port = &altmode->ports[port];515 if (!alt_port->bridge)516 continue;517 518 ret = devm_drm_dp_hpd_bridge_add(dev, alt_port->bridge);519 if (ret)520 return ret;521 }522 523 altmode->client = devm_pmic_glink_client_alloc(dev,524 altmode->owner_id,525 pmic_glink_altmode_callback,526 pmic_glink_altmode_pdr_notify,527 altmode);528 if (IS_ERR(altmode->client))529 return PTR_ERR(altmode->client);530 531 pmic_glink_client_register(altmode->client);532 533 return 0;534}535 536static const struct auxiliary_device_id pmic_glink_altmode_id_table[] = {537 { .name = "pmic_glink.altmode", },538 {},539};540MODULE_DEVICE_TABLE(auxiliary, pmic_glink_altmode_id_table);541 542static struct auxiliary_driver pmic_glink_altmode_driver = {543 .name = "pmic_glink_altmode",544 .probe = pmic_glink_altmode_probe,545 .id_table = pmic_glink_altmode_id_table,546};547 548module_auxiliary_driver(pmic_glink_altmode_driver);549 550MODULE_DESCRIPTION("Qualcomm PMIC GLINK Altmode driver");551MODULE_LICENSE("GPL");552