]> git.pld-linux.org Git - packages/kernel.git/blobdiff - kernel-pinebook-pro.patch
up to 5.19.4
[packages/kernel.git] / kernel-pinebook-pro.patch
index d4f6dbb01b0643d7f0237ace7808279d836f1b29..8ed145382c4b55b4b1fe24ce41b0a6ff4ebff216 100644 (file)
-From c223fa5f3cded17156fb781c1861a92349c4c5be Mon Sep 17 00:00:00 2001
-From: Tobias Schramm <t.schramm@manjaro.org>
-Date: Thu, 28 May 2020 14:01:59 +0200
-Subject: [PATCH] leds: Add support for inverted LED triggers
+From 8149051c34bc3d4c55adc56d04ffb7f7a04c2fd9 Mon Sep 17 00:00:00 2001
+From: Dan Johansen <strit@manjaro.org>
+Date: Sun, 2 Jan 2022 16:45:28 +0100
+Subject: [PATCH 1/2] Add megis extcon changes to fusb302
 
-Needs to be changed for upstream, invert via sysfs not trigger duplication
-
-Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
+Signed-off-by: Dan Johansen <strit@manjaro.org>
 ---
- drivers/leds/led-core.c     |   1 +
- drivers/leds/led-triggers.c | 149 +++++++++++++++++++++++++++---------
- include/linux/leds.h        |   1 +
- 3 files changed, 113 insertions(+), 38 deletions(-)
+ drivers/phy/rockchip/phy-rockchip-typec.c |  5 +++
+ drivers/usb/typec/Kconfig                 |  7 ++++
+ drivers/usb/typec/Makefile                |  1 +
+ drivers/usb/typec/tcpm/fusb302.c          | 47 ++++++++++++++++-------
+ drivers/usb/typec/tcpm/fusb302_reg.h      | 16 ++++----
+ 5 files changed, 53 insertions(+), 23 deletions(-)
 
-diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
-index c4e780bdb385..3973676d6f1e 100644
---- a/drivers/leds/led-core.c
-+++ b/drivers/leds/led-core.c
-@@ -177,6 +177,7 @@ static void led_blink_setup(struct led_classdev *led_cdev,
-                    unsigned long *delay_off)
- {
-       if (!test_bit(LED_BLINK_ONESHOT, &led_cdev->work_flags) &&
-+          !test_bit(LED_BLINK_INVERT, &led_cdev->work_flags) &&
-           led_cdev->blink_set &&
-           !led_cdev->blink_set(led_cdev, delay_on, delay_off))
-               return;
-diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
-index 91da90cfb11d..7f2898a0e1e3 100644
---- a/drivers/leds/led-triggers.c
-+++ b/drivers/leds/led-triggers.c
-@@ -27,20 +27,89 @@ LIST_HEAD(trigger_list);
-  /* Used by LED Class */
-+
- static inline bool
- trigger_relevant(struct led_classdev *led_cdev, struct led_trigger *trig)
- {
-       return !trig->trigger_type || trig->trigger_type == led_cdev->trigger_type;
- }
-+
-+#define TRIGGER_INVERT_SUFFIX "-inverted"
-+
-+/*
-+ * Check suffix of trigger name agains TRIGGER_INVERT_SUFFIX
-+ */
-+static bool led_trigger_is_inverted(const char *trigname)
-+{
-+      if (strlen(trigname) >= strlen(TRIGGER_INVERT_SUFFIX)) {
-+              return !strcmp(trigname + strlen(trigname) -
-+                               strlen(TRIGGER_INVERT_SUFFIX),
-+                              TRIGGER_INVERT_SUFFIX);
-+      }
-+
-+      return false;
-+}
-+
-+/*
-+ * Get length of trigger name name without TRIGGER_INVERT_SUFFIX
-+ */
-+static size_t led_trigger_get_name_len(const char *trigname)
-+{
-+      // Subtract length of TRIGGER_INVERT_SUFFIX if trigger is inverted
-+      if (led_trigger_is_inverted(trigname))
-+              return strlen(trigname) - strlen(TRIGGER_INVERT_SUFFIX);
-+      return strlen(trigname);
-+}
-+
-+/*
-+ * Find and set led trigger by name
-+ */
-+static int led_trigger_set_str_(struct led_classdev *led_cdev,
-+                             const char *trigname, bool lock)
-+{
-+      struct led_trigger *trig;
-+      bool inverted = led_trigger_is_inverted(trigname);
-+      size_t len = led_trigger_get_name_len(trigname);
-+
-+      down_read(&triggers_list_lock);
-+      list_for_each_entry(trig, &trigger_list, next_trig) {
-+              /* Compare trigger name without inversion suffix */
-+              if (strlen(trig->name) == len &&
-+                  !strncmp(trigname, trig->name, len) &&
-+                  trigger_relevant(led_cdev, trig)) {
-+                      if (lock)
-+                              down_write(&led_cdev->trigger_lock);
-+                      led_trigger_set(led_cdev, trig);
-+                      if (inverted)
-+                              led_cdev->flags |= LED_INVERT_TRIGGER;
-+                      else
-+                              led_cdev->flags &= ~LED_INVERT_TRIGGER;
-+                      if (lock)
-+                              up_write(&led_cdev->trigger_lock);
-+
-+                      up_read(&triggers_list_lock);
-+                      return 0;
-+              }
+diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c
+index d2bbdc96a167..fa10ee9a5794 100644
+--- a/drivers/phy/rockchip/phy-rockchip-typec.c
++++ b/drivers/phy/rockchip/phy-rockchip-typec.c
+@@ -350,6 +350,7 @@ struct usb3phy_reg {
+  * struct rockchip_usb3phy_port_cfg - usb3-phy port configuration.
+  * @reg: the base address for usb3-phy config.
+  * @typec_conn_dir: the register of type-c connector direction.
++ * @typec_conn_dir_sel: the register of type-c connector direction source.
+  * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable.
+  * @external_psm: the register of type-c phy external psm clock.
+  * @pipe_status: the register of type-c phy pipe status.
+@@ -360,6 +361,7 @@ struct usb3phy_reg {
+ struct rockchip_usb3phy_port_cfg {
+       unsigned int reg;
+       struct usb3phy_reg typec_conn_dir;
++      struct usb3phy_reg typec_conn_dir_sel;
+       struct usb3phy_reg usb3tousb2_en;
+       struct usb3phy_reg external_psm;
+       struct usb3phy_reg pipe_status;
+@@ -434,6 +436,7 @@ static const struct rockchip_usb3phy_port_cfg rk3399_usb3phy_port_cfgs[] = {
+       {
+               .reg = 0xff7c0000,
+               .typec_conn_dir = { 0xe580, 0, 16 },
++              .typec_conn_dir_sel     = { 0xe580, 8, 16+8 },
+               .usb3tousb2_en  = { 0xe580, 3, 19 },
+               .external_psm   = { 0xe588, 14, 30 },
+               .pipe_status    = { 0xe5c0, 0, 0 },
+@@ -444,6 +447,7 @@ static const struct rockchip_usb3phy_port_cfg rk3399_usb3phy_port_cfgs[] = {
+       {
+               .reg = 0xff800000,
+               .typec_conn_dir = { 0xe58c, 0, 16 },
++              .typec_conn_dir_sel     = { 0xe58c, 8, 16+8 },
+               .usb3tousb2_en  = { 0xe58c, 3, 19 },
+               .external_psm   = { 0xe594, 14, 30 },
+               .pipe_status    = { 0xe5c0, 16, 16 },
+@@ -739,6 +743,7 @@ static int tcphy_phy_init(struct rockchip_typec_phy *tcphy, u8 mode)
+       reset_control_deassert(tcphy->tcphy_rst);
++      property_enable(tcphy, &cfg->typec_conn_dir_sel, 0);
+       property_enable(tcphy, &cfg->typec_conn_dir, tcphy->flip);
+       tcphy_dp_aux_set_flip(tcphy);
+diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig
+index ab480f38523a..01ecc5e590f1 100644
+--- a/drivers/usb/typec/Kconfig
++++ b/drivers/usb/typec/Kconfig
+@@ -88,6 +88,13 @@ config TYPEC_QCOM_PMIC
+         If you choose to build this driver as a dynamically linked module, the
+         module will be called wusb3801.ko.
++config TYPEC_EXTCON
++      tristate "Type-C switch/mux -> extcon interface bridge driver"
++      depends on USB_ROLE_SWITCH
++      help
++        Say Y or M here if your system needs bridging between typec class
++        and extcon interfaces.
++
+ source "drivers/usb/typec/mux/Kconfig"
+ source "drivers/usb/typec/altmodes/Kconfig"
+diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile
+index a0adb8947a30..d9d829386b73 100644
+--- a/drivers/usb/typec/Makefile
++++ b/drivers/usb/typec/Makefile
+@@ -8,4 +8,5 @@ obj-$(CONFIG_TYPEC_TPS6598X)   += tipd/
+ obj-$(CONFIG_TYPEC_STUSB160X)         += stusb160x.o
+ obj-$(CONFIG_TYPEC_RT1719)    += rt1719.o
+ obj-$(CONFIG_TYPEC_WUSB3801)  += wusb3801.o
++obj-$(CONFIG_TYPEC_EXTCON)    += typec-extcon.o
+ obj-$(CONFIG_TYPEC)           += mux/
+diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
+index 72f9001b0792..cb26793f90f8 100644
+--- a/drivers/usb/typec/tcpm/fusb302.c
++++ b/drivers/usb/typec/tcpm/fusb302.c
+@@ -440,6 +440,16 @@ static int tcpm_get_current_limit(struct tcpc_dev *dev)
+       int current_limit = 0;
+       unsigned long timeout;
++      /*
++       * To avoid cycles in OF dependencies, we get extcon when necessary
++       * outside of probe function.
++       */
++      if (of_property_read_bool(chip->dev->of_node, "extcon") && !chip->extcon) {
++              chip->extcon = extcon_get_edev_by_phandle(chip->dev, 0);
++              if (IS_ERR(chip->extcon))
++                      chip->extcon = NULL;
 +      }
-+      /* we come here only if trigname matches no trigger */
-+      up_read(&triggers_list_lock);
-+      return -EINVAL;
-+}
-+
-+#define led_trigger_set_str(cdev, name) led_trigger_set_str_(cdev, name, true)
-+#define led_trigger_set_str_unlocked(cdev, name) \
-+              led_trigger_set_str_(cdev, name, false)
 +
-+
- ssize_t led_trigger_write(struct file *filp, struct kobject *kobj,
-                         struct bin_attribute *bin_attr, char *buf,
-                         loff_t pos, size_t count)
- {
-       struct device *dev = kobj_to_dev(kobj);
-       struct led_classdev *led_cdev = dev_get_drvdata(dev);
--      struct led_trigger *trig;
-       int ret = count;
-+      char *name;
-       mutex_lock(&led_cdev->led_access);
-@@ -54,20 +123,10 @@ ssize_t led_trigger_write(struct file *filp, struct kobject *kobj,
-               goto unlock;
-       }
--      down_read(&triggers_list_lock);
--      list_for_each_entry(trig, &trigger_list, next_trig) {
--              if (sysfs_streq(buf, trig->name) && trigger_relevant(led_cdev, trig)) {
--                      down_write(&led_cdev->trigger_lock);
--                      led_trigger_set(led_cdev, trig);
--                      up_write(&led_cdev->trigger_lock);
--
--                      up_read(&triggers_list_lock);
--                      goto unlock;
--              }
--      }
--      /* we come here only if buf matches no trigger */
--      ret = -EINVAL;
--      up_read(&triggers_list_lock);
-+      name = strim(buf);
-+      ret = led_trigger_set_str(led_cdev, name);
-+      if (!ret)
-+              ret = count;
- unlock:
-       mutex_unlock(&led_cdev->led_access);
-@@ -99,16 +158,25 @@ static int led_trigger_format(char *buf, size_t size,
-                                      led_cdev->trigger ? "none" : "[none]");
+       if (!chip->extcon)
+               return 0;
  
-       list_for_each_entry(trig, &trigger_list, next_trig) {
--              bool hit;
-+              bool hit = led_cdev->trigger == trig;
-+              bool inverted = led_cdev->flags & LED_INVERT_TRIGGER;
-               if (!trigger_relevant(led_cdev, trig))
-                       continue;
--              hit = led_cdev->trigger && !strcmp(led_cdev->trigger->name, trig->name);
-+              /* print non-inverted trigger */
-+              len += led_trigger_snprintf(buf + len, size - len,
-+                                          " %s%s%s",
-+                                          hit && !inverted ? "[" : "",
-+                                          trig->name,
-+                                          hit && !inverted ? "]" : "");
-+              /* print inverted trigger */
-               len += led_trigger_snprintf(buf + len, size - len,
--                                          " %s%s%s", hit ? "[" : "",
--                                          trig->name, hit ? "]" : "");
-+                                          " %s%s"TRIGGER_INVERT_SUFFIX"%s",
-+                                          hit && inverted ? "[" : "",
-+                                          trig->name,
-+                                          hit && inverted ? "]" : "");
-       }
-       len += led_trigger_snprintf(buf + len, size - len, "\n");
-@@ -245,22 +313,15 @@ EXPORT_SYMBOL_GPL(led_trigger_remove);
- void led_trigger_set_default(struct led_classdev *led_cdev)
+@@ -498,6 +508,7 @@ static int fusb302_set_toggling(struct fusb302_chip *chip,
+                               enum toggling_mode mode)
  {
--      struct led_trigger *trig;
-+      bool found;
-       if (!led_cdev->default_trigger)
-               return;
-       down_read(&triggers_list_lock);
--      down_write(&led_cdev->trigger_lock);
--      list_for_each_entry(trig, &trigger_list, next_trig) {
--              if (!strcmp(led_cdev->default_trigger, trig->name) &&
--                  trigger_relevant(led_cdev, trig)) {
--                      led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
--                      led_trigger_set(led_cdev, trig);
--                      break;
--              }
--      }
--      up_write(&led_cdev->trigger_lock);
-+      found = !led_trigger_set_str(led_cdev, led_cdev->default_trigger);
-+      if (found)
-+              led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
-       up_read(&triggers_list_lock);
- }
- EXPORT_SYMBOL_GPL(led_trigger_set_default);
-@@ -305,12 +366,15 @@ int led_trigger_register(struct led_trigger *trig)
-       /* Register with any LEDs that have this as a default trigger */
-       down_read(&leds_list_lock);
-       list_for_each_entry(led_cdev, &leds_list, node) {
-+              bool found;
-+
-               down_write(&led_cdev->trigger_lock);
-               if (!led_cdev->trigger && led_cdev->default_trigger &&
--                  !strcmp(led_cdev->default_trigger, trig->name) &&
-                   trigger_relevant(led_cdev, trig)) {
--                      led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
--                      led_trigger_set(led_cdev, trig);
-+                      found = !led_trigger_set_str_unlocked(led_cdev,
-+                                      led_cdev->default_trigger);
-+                      if (found)
-+                              led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
-               }
-               up_write(&led_cdev->trigger_lock);
+       int ret = 0;
++      u8 reg;
+       /* first disable toggling */
+       ret = fusb302_i2c_clear_bits(chip, FUSB_REG_CONTROL2,
+@@ -556,6 +567,12 @@ static int fusb302_set_toggling(struct fusb302_chip *chip,
+       } else {
+               /* Datasheet says vconn MUST be off when toggling */
+               WARN(chip->vconn_on, "Vconn is on during toggle start");
++
++              /* clear interrupts */
++                ret = fusb302_i2c_read(chip, FUSB_REG_INTERRUPT, &reg);
++              if (ret < 0)
++                      return ret;
++
+               /* unmask TOGDONE interrupt */
+               ret = fusb302_i2c_clear_bits(chip, FUSB_REG_MASKA,
+                                            FUSB_REG_MASKA_TOGDONE);
+@@ -635,6 +652,14 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc)
+               goto done;
        }
-@@ -383,8 +447,14 @@ void led_trigger_event(struct led_trigger *trig,
-               return;
  
-       read_lock_irqsave(&trig->leddev_list_lock, flags);
--      list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list)
--              led_set_brightness(led_cdev, brightness);
-+      list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) {
-+              /* Reverse brightness if LED is inverted */
-+              if (led_cdev->flags & LED_INVERT_TRIGGER)
-+                      led_set_brightness(led_cdev,
-+                              led_cdev->max_brightness - brightness);
-+              else
-+                      led_set_brightness(led_cdev, brightness);
++      /* adjust current for SRC */
++      ret = fusb302_set_src_current(chip, cc_src_current[cc]);
++      if (ret < 0) {
++              fusb302_log(chip, "cannot set src current %s, ret=%d",
++                          typec_cc_status_name[cc], ret);
++              goto done;
 +      }
-       read_unlock_irqrestore(&trig->leddev_list_lock, flags);
- }
- EXPORT_SYMBOL_GPL(led_trigger_event);
-@@ -402,10 +472,13 @@ static void led_trigger_blink_setup(struct led_trigger *trig,
-       read_lock_irqsave(&trig->leddev_list_lock, flags);
-       list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) {
--              if (oneshot)
-+              bool trigger_inverted =
-+                      !!(led_cdev->flags & LED_INVERT_TRIGGER);
-+              if (oneshot) {
-+                      /* use logical xnor to determine inversion parameter */
-                       led_blink_set_oneshot(led_cdev, delay_on, delay_off,
--                                            invert);
--              else
-+                                            (!!invert) == trigger_inverted);
-+              } else
-                       led_blink_set(led_cdev, delay_on, delay_off);
++
+       ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES0,
+                                    switches0_mask, switches0_data);
+       if (ret < 0) {
+@@ -645,14 +670,6 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc)
+       chip->cc1 = TYPEC_CC_OPEN;
+       chip->cc2 = TYPEC_CC_OPEN;
+-      /* adjust current for SRC */
+-      ret = fusb302_set_src_current(chip, cc_src_current[cc]);
+-      if (ret < 0) {
+-              fusb302_log(chip, "cannot set src current %s, ret=%d",
+-                          typec_cc_status_name[cc], ret);
+-              goto done;
+-      }
+-
+       /* enable/disable interrupts, BC_LVL for SNK and COMP_CHNG for SRC */
+       switch (cc) {
+       case TYPEC_CC_RP_DEF:
+@@ -1528,14 +1545,16 @@ static void fusb302_irq_work(struct work_struct *work)
+                   "IRQ: 0x%02x, a: 0x%02x, b: 0x%02x, status0: 0x%02x",
+                   interrupt, interrupta, interruptb, status0);
+-      if (interrupt & FUSB_REG_INTERRUPT_VBUSOK) {
+-              vbus_present = !!(status0 & FUSB_REG_STATUS0_VBUSOK);
++      vbus_present = !!(status0 & FUSB_REG_STATUS0_VBUSOK);
++      if (interrupt & FUSB_REG_INTERRUPT_VBUSOK)
+               fusb302_log(chip, "IRQ: VBUS_OK, vbus=%s",
+                           vbus_present ? "On" : "Off");
+-              if (vbus_present != chip->vbus_present) {
+-                      chip->vbus_present = vbus_present;
+-                      tcpm_vbus_change(chip->tcpm_port);
+-              }
++      if (vbus_present != chip->vbus_present) {
++              chip->vbus_present = vbus_present;
++              if (!(interrupt & FUSB_REG_INTERRUPT_VBUSOK))
++              fusb302_log(chip, "IRQ: VBUS changed without interrupt, vbus=%s",
++                          vbus_present ? "On" : "Off");
++              tcpm_vbus_change(chip->tcpm_port);
        }
-       read_unlock_irqrestore(&trig->leddev_list_lock, flags);
-diff --git a/include/linux/leds.h b/include/linux/leds.h
-index 6a8d6409c993..9cbf42cf08e8 100644
---- a/include/linux/leds.h
-+++ b/include/linux/leds.h
-@@ -79,6 +79,7 @@ struct led_classdev {
- #define LED_BRIGHT_HW_CHANGED BIT(21)
- #define LED_RETAIN_AT_SHUTDOWN        BIT(22)
- #define LED_INIT_DEFAULT_TRIGGER BIT(23)
-+#define LED_INVERT_TRIGGER    BIT(24)
  
-       /* set_brightness_work / blink_timer flags, atomic, private. */
-       unsigned long           work_flags;
+       if ((interrupta & FUSB_REG_INTERRUPTA_TOGDONE) && intr_togdone) {
+diff --git a/drivers/usb/typec/tcpm/fusb302_reg.h b/drivers/usb/typec/tcpm/fusb302_reg.h
+index edc0e4b0f1e6..f37d226c5027 100644
+--- a/drivers/usb/typec/tcpm/fusb302_reg.h
++++ b/drivers/usb/typec/tcpm/fusb302_reg.h
+@@ -27,14 +27,13 @@
+ #define FUSB_REG_SWITCHES1_TXCC2_EN           BIT(1)
+ #define FUSB_REG_SWITCHES1_TXCC1_EN           BIT(0)
+ #define FUSB_REG_MEASURE                      0x04
+-#define FUSB_REG_MEASURE_MDAC5                        BIT(7)
+-#define FUSB_REG_MEASURE_MDAC4                        BIT(6)
+-#define FUSB_REG_MEASURE_MDAC3                        BIT(5)
+-#define FUSB_REG_MEASURE_MDAC2                        BIT(4)
+-#define FUSB_REG_MEASURE_MDAC1                        BIT(3)
+-#define FUSB_REG_MEASURE_MDAC0                        BIT(2)
+-#define FUSB_REG_MEASURE_VBUS                 BIT(1)
+-#define FUSB_REG_MEASURE_XXXX5                        BIT(0)
++#define FUSB_REG_MEASURE_VBUS                 BIT(6)
++#define FUSB_REG_MEASURE_MDAC5                        BIT(5)
++#define FUSB_REG_MEASURE_MDAC4                        BIT(4)
++#define FUSB_REG_MEASURE_MDAC3                        BIT(3)
++#define FUSB_REG_MEASURE_MDAC2                        BIT(2)
++#define FUSB_REG_MEASURE_MDAC1                        BIT(1)
++#define FUSB_REG_MEASURE_MDAC0                        BIT(0)
+ #define FUSB_REG_CONTROL0                     0x06
+ #define FUSB_REG_CONTROL0_TX_FLUSH            BIT(6)
+ #define FUSB_REG_CONTROL0_INT_MASK            BIT(5)
+@@ -105,7 +104,6 @@
+ #define FUSB_REG_STATUS0A_RX_SOFT_RESET               BIT(1)
+ #define FUSB_REG_STATUS0A_RX_HARD_RESET               BIT(0)
+ #define FUSB_REG_STATUS1A                     0x3D
+-#define FUSB_REG_STATUS1A_TOGSS                       BIT(3)
+ #define FUSB_REG_STATUS1A_TOGSS_RUNNING               0x0
+ #define FUSB_REG_STATUS1A_TOGSS_SRC1          0x1
+ #define FUSB_REG_STATUS1A_TOGSS_SRC2          0x2
 -- 
-GitLab
-
-From 90a117ec260f54078aabcf2c1cde72f4425116ba Mon Sep 17 00:00:00 2001
-From: Tobias Schramm <t.schramm@manjaro.org>
-Date: Thu, 28 May 2020 14:12:56 +0200
-Subject: [PATCH] tty: serdev: support shutdown op
+2.34.1
 
-Allow serdev drivers to register a shutdown handler
+From 6af2e6a2d59bd755234e5e15a47dfa669788143c Mon Sep 17 00:00:00 2001
+From: Dan Johansen <strit@manjaro.org>
+Date: Sun, 2 Jan 2022 16:47:40 +0100
+Subject: [PATCH 2/2] usb: typec: Add megis typex to extcon bridge driver
 
-Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
+Signed-off-by: Dan Johansen <strit@manjaro.org>
 ---
- drivers/tty/serdev/core.c | 11 +++++++++++
- include/linux/serdev.h    |  1 +
- 2 files changed, 12 insertions(+)
-
-diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
-index c5f0d936b003..37e45c356540 100644
---- a/drivers/tty/serdev/core.c
-+++ b/drivers/tty/serdev/core.c
-@@ -432,11 +432,22 @@ static int serdev_drv_remove(struct device *dev)
-       return 0;
- }
-+static void serdev_drv_shutdown(struct device *dev)
+ drivers/usb/typec/typec-extcon.c | 337 +++++++++++++++++++++++++++++++
+ 1 file changed, 337 insertions(+)
+ create mode 100644 drivers/usb/typec/typec-extcon.c
+
+diff --git a/drivers/usb/typec/typec-extcon.c b/drivers/usb/typec/typec-extcon.c
+new file mode 100644
+index 000000000000..143ff2486f2f
+--- /dev/null
++++ b/drivers/usb/typec/typec-extcon.c
+@@ -0,0 +1,337 @@
++/*
++ * typec -> extcon bridge
++ * Copyright (c) 2021 OndÅ™ej Jirman <megi@xff.cz>
++ *
++ * This driver bridges standard type-c interfaces to drivers that
++ * expect extcon interface.
++ */
++
++#include <linux/delay.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/power_supply.h>
++#include <linux/platform_device.h>
++#include <linux/usb/pd.h>
++#include <linux/usb/role.h>
++#include <linux/usb/typec.h>
++#include <linux/usb/typec_dp.h>
++#include <linux/usb/typec_mux.h>
++#include <linux/extcon-provider.h>
++
++struct typec_extcon {
++        struct device *dev;
++
++      /* consumers */
++      struct usb_role_switch *role_sw;
++        struct typec_switch_dev *sw;
++        struct typec_mux_dev *mux;
++
++      /* providers */
++      struct extcon_dev *extcon;
++      struct notifier_block extcon_nb;
++
++      /* cached state from typec controller */
++      enum usb_role role;
++      enum typec_orientation orientation;
++      struct typec_altmode alt;
++      unsigned long mode;
++      bool has_alt;
++      struct mutex lock;
++};
++
++static const unsigned int typec_extcon_cable[] = {
++      EXTCON_DISP_DP,
++
++      EXTCON_USB,
++      EXTCON_USB_HOST,
++
++      EXTCON_CHG_USB_SDP,
++      EXTCON_CHG_USB_CDP,
++      EXTCON_CHG_USB_DCP,
++      EXTCON_CHG_USB_ACA,
++
++      EXTCON_NONE,
++};
++
++static void typec_extcon_set_cable(struct typec_extcon *tce, int id, bool on,
++                                 union extcon_property_value prop_ss,
++                                 union extcon_property_value prop_or)
 +{
-+      const struct serdev_device_driver *sdrv;
-+      if (dev->driver) {
-+              sdrv = to_serdev_device_driver(dev->driver);
-+              if (sdrv->shutdown)
-+                      sdrv->shutdown(to_serdev_device(dev));
++      union extcon_property_value cur_ss, cur_or;
++      bool prop_diff = false;
++      int ret;
++
++      ret = extcon_get_property(tce->extcon, id,
++                                EXTCON_PROP_USB_SS, &cur_ss);
++      if (ret || cur_ss.intval != prop_ss.intval)
++              prop_diff = true;
++
++      ret = extcon_get_property(tce->extcon, id,
++                                EXTCON_PROP_USB_TYPEC_POLARITY, &cur_or);
++      if (ret || cur_or.intval != prop_or.intval)
++              prop_diff = true;
++
++      if (!on && extcon_get_state(tce->extcon, id)) {
++              extcon_set_state_sync(tce->extcon, id, false);
++      } else if (on && (!extcon_get_state(tce->extcon, id) || prop_diff)) {
++              extcon_set_state(tce->extcon, id, true);
++              extcon_set_property(tce->extcon, id,
++                                  EXTCON_PROP_USB_SS, prop_ss);
++              extcon_set_property(tce->extcon, id,
++                                  EXTCON_PROP_USB_TYPEC_POLARITY, prop_or);
++              extcon_sync(tce->extcon, id);
 +      }
 +}
 +
- static struct bus_type serdev_bus_type = {
-       .name           = "serial",
-       .match          = serdev_device_match,
-       .probe          = serdev_drv_probe,
-       .remove         = serdev_drv_remove,
-+      .shutdown       = serdev_drv_shutdown,
- };
- /**
-diff --git a/include/linux/serdev.h b/include/linux/serdev.h
-index 9f14f9c12ec4..94050561325c 100644
---- a/include/linux/serdev.h
-+++ b/include/linux/serdev.h
-@@ -63,6 +63,7 @@ struct serdev_device_driver {
-       struct device_driver driver;
-       int     (*probe)(struct serdev_device *);
-       void    (*remove)(struct serdev_device *);
-+      void    (*shutdown)(struct serdev_device *);
- };
- static inline struct serdev_device_driver *to_serdev_device_driver(struct device_driver *d)
--- 
-GitLab
-
-From 4381cb3400bd61288d2122f3eb74711963885323 Mon Sep 17 00:00:00 2001
-From: Tobias Schramm <t.schramm@manjaro.org>
-Date: Thu, 28 May 2020 14:14:06 +0200
-Subject: [PATCH] bluetooth: hci_serdev: Clear registered bit on unregister
-
-Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
----
- drivers/bluetooth/hci_serdev.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c
-index ef96ad06fa54..95c723c0ea01 100644
---- a/drivers/bluetooth/hci_serdev.c
-+++ b/drivers/bluetooth/hci_serdev.c
-@@ -395,5 +395,7 @@ void hci_uart_unregister_device(struct hci_uart *hu)
-               clear_bit(HCI_UART_PROTO_READY, &hu->flags);
-               serdev_device_close(hu->serdev);
-       }
-+
-+      clear_bit(HCI_UART_REGISTERED, &hu->flags);
- }
- EXPORT_SYMBOL_GPL(hci_uart_unregister_device);
--- 
-GitLab
-
-From 4065c5018d7d4fc7d6ea51056a954f23320688ca Mon Sep 17 00:00:00 2001
-From: Tobias Schramm <t.schramm@manjaro.org>
-Date: Thu, 28 May 2020 14:15:08 +0200
-Subject: [PATCH] bluetooth: hci_bcm: disable power on shutdown
-
-Firmware behaves wonky when not power cycled over reboots
-
-Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
----
- drivers/bluetooth/hci_bcm.c | 18 ++++++++++++++++++
- 1 file changed, 18 insertions(+)
-
-diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c
-index 8ea5ca8d71d6..6d5871992f79 100644
---- a/drivers/bluetooth/hci_bcm.c
-+++ b/drivers/bluetooth/hci_bcm.c
-@@ -1469,6 +1469,23 @@ static void bcm_serdev_remove(struct serdev_device *serdev)
-       hci_uart_unregister_device(&bcmdev->serdev_hu);
- }
-+static void bcm_serdev_shutdown(struct serdev_device *serdev)
++static int typec_extcon_sync_extcon(struct typec_extcon *tce)
 +{
-+      struct bcm_device *bcmdev = serdev_device_get_drvdata(serdev);
++      union extcon_property_value prop_ss, prop_or;
++      bool has_dp = false;
 +
-+/*
-+      if (test_bit(HCI_UART_REGISTERED, &bcmdev->hu->flags)) {
-+              hci_uart_unregister_device(&bcmdev->serdev_hu);
++        mutex_lock(&tce->lock);
++
++      /* connector is disconnected */
++      if (tce->orientation == TYPEC_ORIENTATION_NONE) {
++              typec_extcon_set_cable(tce, EXTCON_USB, false, prop_ss, prop_or);
++              typec_extcon_set_cable(tce, EXTCON_USB_HOST, false, prop_ss, prop_or);
++              typec_extcon_set_cable(tce, EXTCON_DISP_DP, false, prop_ss, prop_or);
++
++              extcon_set_state_sync(tce->extcon, EXTCON_CHG_USB_SDP, false);
++              extcon_set_state_sync(tce->extcon, EXTCON_CHG_USB_DCP, false);
++              extcon_set_state_sync(tce->extcon, EXTCON_CHG_USB_CDP, false);
++              extcon_set_state_sync(tce->extcon, EXTCON_CHG_USB_ACA, false);
++
++                goto out_unlock;
 +      }
-+*/
-+      dev_info(bcmdev->dev, "Cutting power to bluetooth module\n");
-+      if (bcm_gpio_set_power(bcmdev, false)) {
-+              dev_err(bcmdev->dev, "Failed to power down\n");
++
++      prop_or.intval = tce->orientation == TYPEC_ORIENTATION_NORMAL ? 0 : 1;
++      prop_ss.intval = 0;
++
++      if (tce->has_alt && tce->alt.svid == USB_TYPEC_DP_SID) {
++              switch (tce->mode) {
++              case TYPEC_STATE_SAFE:
++                      break;
++              case TYPEC_DP_STATE_C:
++              case TYPEC_DP_STATE_E:
++                      has_dp = true;
++                      break;
++              case TYPEC_DP_STATE_D:
++                      has_dp = true;
++                      fallthrough;
++              case TYPEC_STATE_USB:
++                      prop_ss.intval = 1;
++                      break;
++              default:
++                      dev_err(tce->dev, "unhandled mux mode=%lu\n", tce->mode);
++                      break;
++              }
 +      }
-+      usleep_range(500000, 1000000);
-+}
 +
++      typec_extcon_set_cable(tce, EXTCON_USB,
++                      tce->role == USB_ROLE_DEVICE, prop_ss, prop_or);
++      typec_extcon_set_cable(tce, EXTCON_USB_HOST,
++                      tce->role == USB_ROLE_HOST, prop_ss, prop_or);
 +
- #ifdef CONFIG_OF
- static struct bcm_device_data bcm4354_device_data = {
-       .no_early_set_baudrate = true,
-@@ -1494,6 +1511,7 @@ MODULE_DEVICE_TABLE(of, bcm_bluetooth_of_match);
- static struct serdev_device_driver bcm_serdev_driver = {
-       .probe = bcm_serdev_probe,
-       .remove = bcm_serdev_remove,
-+      .shutdown = bcm_serdev_shutdown,
-       .driver = {
-               .name = "hci_uart_bcm",
-               .of_match_table = of_match_ptr(bcm_bluetooth_of_match),
--- 
-GitLab
-
-From f6419edc62979c1e67202b5dc10abd7b22bdedcf Mon Sep 17 00:00:00 2001
-From: Tobias Schramm <t.schramm@manjaro.org>
-Date: Thu, 28 May 2020 14:16:52 +0200
-Subject: [PATCH] mmc: core: pwrseq_simple: disable mmc power on shutdown
-
-Fix for Broadcom SDIO WiFi modules. They misbehave if reinitialized
-without a power cycle.
-
-Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
----
- drivers/mmc/core/pwrseq_simple.c | 19 ++++++++++++++++---
- 1 file changed, 16 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c
-index ea4d3670560e..38fe7e29aba6 100644
---- a/drivers/mmc/core/pwrseq_simple.c
-+++ b/drivers/mmc/core/pwrseq_simple.c
-@@ -80,10 +80,8 @@ static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host)
-               msleep(pwrseq->post_power_on_delay_ms);
- }
--static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
-+static void __mmc_pwrseq_simple_power_off(struct mmc_pwrseq_simple *pwrseq)
- {
--      struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
--
-       mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
-       if (pwrseq->power_off_delay_us)
-@@ -96,6 +94,12 @@ static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
-       }
- }
-+static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
-+{
-+      struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
-+      __mmc_pwrseq_simple_power_off(pwrseq);
++      typec_extcon_set_cable(tce, EXTCON_DISP_DP, has_dp, prop_ss, prop_or);
++
++out_unlock:
++      mutex_unlock(&tce->lock);
++      return 0;
 +}
 +
- static const struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = {
-       .pre_power_on = mmc_pwrseq_simple_pre_power_on,
-       .post_power_on = mmc_pwrseq_simple_post_power_on,
-@@ -151,9 +155,18 @@ static int mmc_pwrseq_simple_remove(struct platform_device *pdev)
-       return 0;
- }
-+static void mmc_pwrseq_simple_shutdown(struct platform_device *pdev)
++static int typec_extcon_sw_set(struct typec_switch_dev *sw,
++                             enum typec_orientation orientation)
 +{
-+      struct mmc_pwrseq_simple *pwrseq = platform_get_drvdata(pdev);
++        struct typec_extcon *tce = typec_switch_get_drvdata(sw);
 +
-+      dev_info(&pdev->dev, "Turning off mmc\n");
-+      __mmc_pwrseq_simple_power_off(pwrseq);
-+}
++      dev_dbg(tce->dev, "SW SET: orientation=%d\n", orientation);
 +
- static struct platform_driver mmc_pwrseq_simple_driver = {
-       .probe = mmc_pwrseq_simple_probe,
-       .remove = mmc_pwrseq_simple_remove,
-+      .shutdown = mmc_pwrseq_simple_shutdown,
-       .driver = {
-               .name = "pwrseq_simple",
-               .of_match_table = mmc_pwrseq_simple_of_match,
--- 
-GitLab
-
-From b0452434e75ecf257bc2ea9a5eb86be68bb56f71 Mon Sep 17 00:00:00 2001
-From: Tobias Schramm <t.schramm@manjaro.org>
-Date: Thu, 28 May 2020 14:23:54 +0200
-Subject: [PATCH] usb: typec: tcpm: add hacky generic altmode support
-
-This is a hack and it is based on extcon. Do not try to mainline
-unless you are in need for some retroactive abortion by the
-maintainers.
-
-Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
----
- drivers/usb/typec/tcpm/tcpm.c | 139 +++++++++++++++++++++++++++++++++-
- 1 file changed, 138 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
-index a6fae1f86505..2908771f4d4e 100644
---- a/drivers/usb/typec/tcpm/tcpm.c
-+++ b/drivers/usb/typec/tcpm/tcpm.c
-@@ -9,6 +9,7 @@
- #include <linux/debugfs.h>
- #include <linux/device.h>
- #include <linux/hrtimer.h>
-+#include <linux/extcon-provider.h>
- #include <linux/jiffies.h>
- #include <linux/kernel.h>
- #include <linux/kthread.h>
-@@ -369,6 +370,11 @@ struct tcpm_port {
-        * SNK_READY for non-pd link.
-        */
-       bool slow_charger_loop;
-+#ifdef CONFIG_EXTCON
-+      struct extcon_dev *extcon;
-+      unsigned int *extcon_cables;
-+#endif
++        mutex_lock(&tce->lock);
++      tce->orientation = orientation;
++        mutex_unlock(&tce->lock);
 +
- #ifdef CONFIG_DEBUG_FS
-       struct dentry *dentry;
-       struct mutex logbuffer_lock;    /* log buffer access lock */
-@@ -654,6 +660,35 @@ static void tcpm_debugfs_exit(const struct tcpm_port *port) { }
- #endif
-+static void tcpm_update_extcon_data(struct tcpm_port *port, bool attached) {
-+#ifdef CONFIG_EXTCON
-+      unsigned int *capability = port->extcon_cables;
-+      if (port->data_role == TYPEC_HOST) {
-+              extcon_set_state(port->extcon, EXTCON_USB, false);
-+              extcon_set_state(port->extcon, EXTCON_USB_HOST, attached);
-+      } else {
-+              extcon_set_state(port->extcon, EXTCON_USB, true);
-+              extcon_set_state(port->extcon, EXTCON_USB_HOST, attached);
-+      }
-+      while (*capability != EXTCON_NONE) {
-+              if (attached) {
-+                      union extcon_property_value val;
-+                      val.intval = (port->polarity == TYPEC_POLARITY_CC2);
-+                      extcon_set_property(port->extcon, *capability,
-+                              EXTCON_PROP_USB_TYPEC_POLARITY, val);
-+              } else {
-+                      extcon_set_state(port->extcon, *capability, false);
-+              }
-+              extcon_sync(port->extcon, *capability);
-+              capability++;
-+      }
-+      tcpm_log(port, "Extcon update (%s): %s, %s",
-+              attached ? "attached" : "detached",
-+              port->data_role == TYPEC_HOST ? "host" : "device",
-+              port->polarity == TYPEC_POLARITY_CC1 ? "normal" : "flipped");
-+#endif
++      typec_extcon_sync_extcon(tce);
++
++        return 0;
 +}
 +
- static void tcpm_set_cc(struct tcpm_port *port, enum typec_cc_status cc)
- {
-       tcpm_log(port, "cc:=%d", cc);
-@@ -881,6 +916,8 @@ static int tcpm_set_roles(struct tcpm_port *port, bool attached,
-       typec_set_data_role(port->typec_port, data);
-       typec_set_pwr_role(port->typec_port, role);
-+      tcpm_update_extcon_data(port, attached);
++static int typec_extcon_mux_set(struct typec_mux_dev *mux,
++                              struct typec_mux_state *state)
++{
++        struct typec_extcon *tce = typec_mux_get_drvdata(mux);
++      struct typec_altmode *alt = state->alt;
 +
-       return 0;
- }
-@@ -1132,7 +1169,7 @@ static void svdm_consume_modes(struct tcpm_port *port, const u32 *p, int cnt)
-               paltmode->mode = i;
-               paltmode->vdo = p[i];
--              tcpm_log(port, " Alternate mode %d: SVID 0x%04x, VDO %d: 0x%08x",
-+              tcpm_log(port, "Alternate mode %d: SVID 0x%04x, VDO %d: 0x%08x",
-                        pmdata->altmodes, paltmode->svid,
-                        paltmode->mode, paltmode->vdo);
-@@ -1154,6 +1191,9 @@ static void tcpm_register_partner_altmodes(struct tcpm_port *port)
-                                modep->altmode_desc[i].svid);
-                       altmode = NULL;
-               }
-+              else
-+                      tcpm_log(port, "Registered altmode 0x%04x", modep->altmode_desc[i].svid);
++      dev_dbg(tce->dev, "MUX SET: state->mode=%lu\n", state->mode);
++      if (alt)
++              dev_dbg(tce->dev, "      ...alt: svid=%04hx mode=%d vdo=%08x active=%u\n",
++                      alt->svid, alt->mode, alt->vdo, alt->active);
 +
-               port->partner_altmode[i] = altmode;
-       }
- }
-@@ -1249,9 +1289,11 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev,
-                       modep->svid_index++;
-                       if (modep->svid_index < modep->nsvids) {
-                               u16 svid = modep->svids[modep->svid_index];
-+                              tcpm_log(port, "More modes available, sending discover");
-                               response[0] = VDO(svid, 1, svdm_version, CMD_DISCOVER_MODES);
-                               rlen = 1;
-                       } else {
-+                              tcpm_log(port, "Got all patner modes, registering");
-                               tcpm_register_partner_altmodes(port);
-                               port->vdm_sm_running = false;
-                       }
-@@ -2836,6 +2878,7 @@ static int tcpm_src_attach(struct tcpm_port *port)
- static void tcpm_typec_disconnect(struct tcpm_port *port)
- {
-       if (port->connected) {
-+              tcpm_update_extcon_data(port, false);
-               typec_unregister_partner(port->partner);
-               port->partner = NULL;
-               port->connected = false;
-@@ -2902,6 +2945,8 @@ static void tcpm_detach(struct tcpm_port *port)
-       }
-       tcpm_reset_port(port);
++        mutex_lock(&tce->lock);
++      tce->mode = state->mode;
++      tce->has_alt = alt != NULL;
++        if (alt)
++              tce->alt = *alt;
++      mutex_unlock(&tce->lock);
 +
-+      tcpm_update_extcon_data(port, false);
- }
- static void tcpm_src_detach(struct tcpm_port *port)
-@@ -4732,6 +4777,64 @@ void tcpm_tcpc_reset(struct tcpm_port *port)
- }
- EXPORT_SYMBOL_GPL(tcpm_tcpc_reset);
-+unsigned int default_supported_cables[] = {
-+      EXTCON_NONE
-+};
++      typec_extcon_sync_extcon(tce);
++
++        return 0;
++}
 +
-+static int tcpm_fw_get_caps_late(struct tcpm_port *port,
-+                          struct fwnode_handle *fwnode)
++static int typec_extcon_usb_set_role(struct usb_role_switch *sw,
++                                   enum usb_role role)
 +{
-+      int ret, i;
-+      ret = fwnode_property_count_u32(fwnode, "typec-altmodes");
-+      if (ret > 0) {
-+              u32 *props;
-+              if (ret % 4) {
-+                      dev_err(port->dev, "Length of typec altmode array must be divisible by 4");
-+                      return -EINVAL;
-+              }
++        struct typec_extcon *tce = usb_role_switch_get_drvdata(sw);
 +
-+              props = devm_kzalloc(port->dev, sizeof(u32) * ret, GFP_KERNEL);
-+              if (!props) {
-+                      dev_err(port->dev, "Failed to allocate memory for altmode properties");
-+                      return -ENOMEM;
-+              }
++      dev_dbg(tce->dev, "ROLE SET: role=%d\n", role);
 +
-+              if(fwnode_property_read_u32_array(fwnode, "typec-altmodes", props, ret) < 0) {
-+                      dev_err(port->dev, "Failed to read altmodes from port");
-+                      return -EINVAL;
-+              }
++        mutex_lock(&tce->lock);
++      tce->role = role;
++      mutex_unlock(&tce->lock);
 +
-+              i = 0;
-+              while (ret > 0 && i < ARRAY_SIZE(port->port_altmode)) {
-+                      struct typec_altmode *alt;
-+                      struct typec_altmode_desc alt_desc = {
-+                              .svid = props[i * 4],
-+                              .mode = props[i * 4 + 1],
-+                              .vdo  = props[i * 4 + 2],
-+                              .roles = props[i * 4 + 3],
-+                      };
++      typec_extcon_sync_extcon(tce);
 +
++        return 0;
++}
 +
-+                      tcpm_log(port, "Adding altmode SVID: 0x%04x, mode: %d, vdo: %u, role: %d",
-+                              alt_desc.svid, alt_desc.mode, alt_desc.vdo, alt_desc.roles);
-+                      alt = typec_port_register_altmode(port->typec_port,
-+                                                        &alt_desc);
-+                      if (IS_ERR(alt)) {
-+                              tcpm_log(port,
-+                                       "%s: failed to register port alternate mode 0x%x",
-+                                       dev_name(port->dev), alt_desc.svid);
-+                              break;
-+                      }
-+                      typec_altmode_set_drvdata(alt, port);
-+                      alt->ops = &tcpm_altmode_ops;
-+                      port->port_altmode[i] = alt;
-+                      i++;
-+                      ret -= 4;
-+              }
-+      }
-+      return 0;
++static int typec_extcon_notifier(struct notifier_block *nb,
++                                       unsigned long action, void *data)
++{
++      struct typec_extcon *tce = container_of(nb, struct typec_extcon, extcon_nb);
++
++      bool sdp = extcon_get_state(tce->extcon, EXTCON_CHG_USB_SDP);
++      bool cdp = extcon_get_state(tce->extcon, EXTCON_CHG_USB_CDP);
++      bool dcp = extcon_get_state(tce->extcon, EXTCON_CHG_USB_DCP);
++      bool usb = extcon_get_state(tce->extcon, EXTCON_USB);
++      bool usb_host = extcon_get_state(tce->extcon, EXTCON_USB_HOST);
++      bool dp = extcon_get_state(tce->extcon, EXTCON_DISP_DP);
++
++      dev_info(tce->dev, "extcon changed sdp=%d cdp=%d dcp=%d usb=%d usb_host=%d dp=%d\n",
++               sdp, cdp, dcp, usb, usb_host, dp);
++
++      return NOTIFY_OK;
 +}
 +
- static int tcpm_fw_get_caps(struct tcpm_port *port,
-                           struct fwnode_handle *fwnode)
- {
-@@ -4742,6 +4845,23 @@ static int tcpm_fw_get_caps(struct tcpm_port *port,
-        */
-       fw_devlink_purge_absent_suppliers(fwnode);
-+#ifdef CONFIG_EXTCON
-+      ret = fwnode_property_count_u32(fwnode, "extcon-cables");
-+      if (ret > 0) {
-+              port->extcon_cables = devm_kzalloc(port->dev, sizeof(u32) * ret, GFP_KERNEL);
-+              if (!port->extcon_cables) {
-+                      dev_err(port->dev, "Failed to allocate memory for extcon cable types. "\
-+                              "Using default tyes");
-+                      goto extcon_default;
-+              }
-+              fwnode_property_read_u32_array(fwnode, "extcon-cables", port->extcon_cables, ret);
-+      } else {
-+extcon_default:
-+              dev_info(port->dev, "No cable types defined, using default cables");
-+              port->extcon_cables = default_supported_cables;
++static int typec_extcon_probe(struct platform_device *pdev)
++{
++        struct typec_switch_desc sw_desc = { };
++        struct typec_mux_desc mux_desc = { };
++        struct usb_role_switch_desc role_desc = { };
++        struct device *dev = &pdev->dev;
++        struct typec_extcon *tce;
++        int ret = 0;
++
++        tce = devm_kzalloc(dev, sizeof(*tce), GFP_KERNEL);
++        if (!tce)
++                return -ENOMEM;
++
++        tce->dev = &pdev->dev;
++      mutex_init(&tce->lock);
++      tce->mode = TYPEC_STATE_SAFE;
++
++      sw_desc.drvdata = tce;
++      sw_desc.fwnode = dev->fwnode;
++      sw_desc.set = typec_extcon_sw_set;
++
++      tce->sw = typec_switch_register(dev, &sw_desc);
++      if (IS_ERR(tce->sw))
++              return dev_err_probe(dev, PTR_ERR(tce->sw),
++                                   "Error registering typec switch\n");
++
++      mux_desc.drvdata = tce;
++      mux_desc.fwnode = dev->fwnode;
++      mux_desc.set = typec_extcon_mux_set;
++
++      tce->mux = typec_mux_register(dev, &mux_desc);
++      if (IS_ERR(tce->mux)) {
++              ret = dev_err_probe(dev, PTR_ERR(tce->mux),
++                                  "Error registering typec mux\n");
++              goto err_sw;
 +      }
-+#endif
 +
-       /* USB data support is optional */
-       ret = fwnode_property_read_string(fwnode, "data-role", &cap_str);
-       if (ret == 0) {
-@@ -5114,6 +5234,17 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
-               goto out_destroy_wq;
-       port->try_role = port->typec_caps.prefer_role;
-+#ifdef CONFIG_EXTCON
-+      port->extcon = devm_extcon_dev_allocate(dev, port->extcon_cables);
-+      if (IS_ERR(port->extcon)) {
-+              dev_err(dev, "Failed to allocate extcon device: %ld", PTR_ERR(port->extcon));
-+              goto out_destroy_wq;
++      role_desc.driver_data = tce;
++      role_desc.fwnode = dev->fwnode;
++      role_desc.name = fwnode_get_name(dev->fwnode);
++      role_desc.set = typec_extcon_usb_set_role;
++
++      tce->role_sw = usb_role_switch_register(dev, &role_desc);
++      if (IS_ERR(tce->role_sw)) {
++              ret = dev_err_probe(dev, PTR_ERR(tce->role_sw),
++                                  "Error registering USB role switch\n");
++              goto err_mux;
 +      }
-+      if((err = devm_extcon_dev_register(dev, port->extcon))) {
-+              dev_err(dev, "Failed to register extcon device: %d", err);
-+              goto out_destroy_wq;
++
++      tce->extcon = devm_extcon_dev_allocate(dev, typec_extcon_cable);
++      if (IS_ERR(tce->extcon)) {
++              ret = PTR_ERR(tce->extcon);
++              goto err_role;
 +      }
-+#endif
-       port->typec_caps.fwnode = tcpc->fwnode;
-       port->typec_caps.revision = 0x0120;     /* Type-C spec release 1.2 */
-@@ -5141,6 +5272,12 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
-                                    &tcpm_altmode_ops, port,
-                                    port->port_altmode, ALTMODE_DISCOVERY_MAX);
-+      err = tcpm_fw_get_caps_late(port, tcpc->fwnode);
-+      if (err < 0) {
-+              dev_err(dev, "Failed to get altmodes from fwnode");
-+              goto out_destroy_wq;
++
++      ret = devm_extcon_dev_register(dev, tce->extcon);
++      if (ret) {
++              ret = dev_err_probe(dev, ret, "failed to register extcon device\n");
++              goto err_role;
 +      }
 +
-       mutex_lock(&port->lock);
-       tcpm_init(port);
-       mutex_unlock(&port->lock);
++      extcon_set_property_capability(tce->extcon, EXTCON_USB,
++                                     EXTCON_PROP_USB_SS);
++      extcon_set_property_capability(tce->extcon, EXTCON_USB,
++                                     EXTCON_PROP_USB_TYPEC_POLARITY);
++      extcon_set_property_capability(tce->extcon, EXTCON_USB_HOST,
++                                     EXTCON_PROP_USB_SS);
++      extcon_set_property_capability(tce->extcon, EXTCON_USB_HOST,
++                                     EXTCON_PROP_USB_TYPEC_POLARITY);
++      extcon_set_property_capability(tce->extcon, EXTCON_DISP_DP,
++                                     EXTCON_PROP_USB_SS);
++      extcon_set_property_capability(tce->extcon, EXTCON_DISP_DP,
++                                     EXTCON_PROP_USB_TYPEC_POLARITY);
++
++      tce->extcon_nb.notifier_call = typec_extcon_notifier;
++      ret = devm_extcon_register_notifier_all(dev, tce->extcon, &tce->extcon_nb);
++      if (ret) {
++              dev_err_probe(dev, ret, "Failed to register extcon notifier\n");
++              goto err_role;
++      }
++
++      return 0;
++
++err_role:
++      usb_role_switch_unregister(tce->role_sw);
++err_mux:
++      typec_mux_unregister(tce->mux);
++err_sw:
++      typec_switch_unregister(tce->sw);
++      return ret;
++}
++
++static int typec_extcon_remove(struct platform_device *pdev)
++{
++        struct typec_extcon *tce = platform_get_drvdata(pdev);
++
++      usb_role_switch_unregister(tce->role_sw);
++      typec_mux_unregister(tce->mux);
++      typec_switch_unregister(tce->sw);
++
++        return 0;
++}
++
++static struct of_device_id typec_extcon_of_match_table[] = {
++        { .compatible = "linux,typec-extcon-bridge" },
++        { },
++};
++MODULE_DEVICE_TABLE(of, typec_extcon_of_match_table);
++
++static struct platform_driver typec_extcon_driver = {
++        .driver = {
++                .name = "typec-extcon",
++                .of_match_table = typec_extcon_of_match_table,
++        },
++        .probe = typec_extcon_probe,
++        .remove = typec_extcon_remove,
++};
++
++module_platform_driver(typec_extcon_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Ondrej Jirman <megous@megous.com>");
++MODULE_DESCRIPTION("typec -> extcon bridge driver");
 -- 
-GitLab
-
-From db4e9ffdb985752ae3c3436ff86f8f376ae8fd22 Mon Sep 17 00:00:00 2001
-From: Tobias Schramm <t.schramm@manjaro.org>
-Date: Thu, 28 May 2020 14:25:32 +0200
-Subject: [PATCH] phy: rockchip: typec: Set extcon capabilities
+2.34.1
 
-Do not mainline, hack.
+From 4c839ce95766910235ff558b2959589c9068917c Mon Sep 17 00:00:00 2001
+From: Dan Johansen <strit@manjaro.org>
+Date: Sun, 2 Jan 2022 19:15:39 +0100
+Subject: [PATCH] arm64: dts: rockchip: add typec extcon hack
 
-Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
+Signed-off-by: Dan Johansen <strit@manjaro.org>
 ---
- drivers/phy/rockchip/phy-rockchip-typec.c | 17 +++++++++++++++++
- 1 file changed, 17 insertions(+)
+ .../boot/dts/rockchip/rk3399-pinebook-pro.dts | 31 +++++++++++++++++--
+ 1 file changed, 29 insertions(+), 2 deletions(-)
 
-diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c
-index 70a31251b202..5385bb4f0bd4 100644
---- a/drivers/phy/rockchip/phy-rockchip-typec.c
-+++ b/drivers/phy/rockchip/phy-rockchip-typec.c
-@@ -40,6 +40,7 @@
- #include <linux/clk-provider.h>
- #include <linux/delay.h>
- #include <linux/extcon.h>
-+#include <linux/extcon-provider.h>
- #include <linux/io.h>
- #include <linux/iopoll.h>
- #include <linux/kernel.h>
-@@ -1160,6 +1161,22 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
-                               dev_err(dev, "Invalid or missing extcon\n");
-                       return PTR_ERR(tcphy->extcon);
-               }
-+      } else {
-+              extcon_set_property_capability(tcphy->extcon, EXTCON_USB,
-+                                             EXTCON_PROP_USB_SS);
-+              extcon_set_property_capability(tcphy->extcon, EXTCON_USB_HOST,
-+                                             EXTCON_PROP_USB_SS);
-+              extcon_set_property_capability(tcphy->extcon, EXTCON_DISP_DP,
-+                                             EXTCON_PROP_USB_SS);
-+              extcon_set_property_capability(tcphy->extcon, EXTCON_USB,
-+                                             EXTCON_PROP_USB_TYPEC_POLARITY);
-+              extcon_set_property_capability(tcphy->extcon, EXTCON_USB_HOST,
-+                                             EXTCON_PROP_USB_TYPEC_POLARITY);
-+              extcon_set_property_capability(tcphy->extcon, EXTCON_DISP_DP,
-+                                             EXTCON_PROP_USB_TYPEC_POLARITY);
-+              extcon_sync(tcphy->extcon, EXTCON_USB);
-+              extcon_sync(tcphy->extcon, EXTCON_USB_HOST);
-+              extcon_sync(tcphy->extcon, EXTCON_DISP_DP);
-       }
+diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
+index c2f021a1a18f..fc33e111bbee 100644
+--- a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
+@@ -384,6 +384,20 @@ mains_charger: dc-charger {
+               pinctrl-names = "default";
+               pinctrl-0 = <&dc_det_pin>;
+       };
++      
++    typec_extcon_bridge: typec-extcon {
++              compatible = "linux,typec-extcon-bridge";
++              usb-role-switch;
++              orientation-switch;
++              mode-switch;
++              svid = /bits/ 16 <0xff01>;
++      };
++};
++
++&cdn_dp {
++      status = "okay";
++      extcon = <&typec_extcon_bridge>;
++      phys = <&tcphy0_dp>;
+ };
+ &cpu_b0 {
+@@ -705,6 +719,8 @@ fusb0: fusb30x@22 {
+               pinctrl-names = "default";
+               pinctrl-0 = <&fusb0_int_pin>;
+               vbus-supply = <&vbus_typec>;
++              extcon = <&typec_extcon_bridge>;
++              usb-role-switch = <&typec_extcon_bridge>;
+               connector {
+                       compatible = "usb-c-connector";
+@@ -713,10 +729,20 @@ connector {
+                       op-sink-microwatt = <1000000>;
+                       power-role = "dual";
+                       sink-pdos =
+-                              <PDO_FIXED(5000, 2500, PDO_FIXED_USB_COMM)>;
++                              <PDO_FIXED(5000, 2500, PDO_FIXED_USB_COMM | PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP)>;
+                       source-pdos =
+-                              <PDO_FIXED(5000, 1400, PDO_FIXED_USB_COMM)>;
++                              <PDO_FIXED(5000, 1400, PDO_FIXED_USB_COMM | PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP)>;
+                       try-power-role = "sink";
++                      
++                      mode-switch = <&typec_extcon_bridge>;
++                      orientation-switch = <&typec_extcon_bridge>;
++
++                      altmodes {
++                              dp {
++                                      svid = <0xff01>;
++                                      vdo = <0x0c0046>;
++                              };
++                      };
+                       ports {
+                               #address-cells = <1>;
+@@ -984,6 +1010,7 @@ spiflash: flash@0 {
+ };
+ &tcphy0 {
++      extcon = <&typec_extcon_bridge>;
+       status = "okay";
+ };
  
-       pm_runtime_enable(dev);
 -- 
-GitLab
+2.34.1
 
-From fd739ae47f9ea780a1e161a478e241df06eaff7e Mon Sep 17 00:00:00 2001
-From: Tobias Schramm <t.schramm@manjaro.org>
-Date: Thu, 28 May 2020 14:26:27 +0200
-Subject: [PATCH] usb: typec: altmodes: displayport: Add hacky, generic altmode
- detection
+From: Hugh Cole-Baker <sigmaris@gmail.com>
+Subject: [PATCH v2 1/3] drm/rockchip: define gamma registers for RK3399
+Date: Tue, 19 Oct 2021 22:58:41 +0100
 
-Do not mainline, hack.
+The VOP on RK3399 has a different approach from previous versions for
+setting a gamma lookup table, using an update_gamma_lut register. As
+this differs from RK3288, give RK3399 its own set of "common" register
+definitions.
 
-Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
+Signed-off-by: Hugh Cole-Baker <sigmaris@gmail.com>
 ---
- drivers/usb/typec/altmodes/displayport.c | 55 ++++++++++++++++++++++--
- 1 file changed, 52 insertions(+), 3 deletions(-)
 
-diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c
-index e62e5e3da01e..a3d03db476aa 100644
---- a/drivers/usb/typec/altmodes/displayport.c
-+++ b/drivers/usb/typec/altmodes/displayport.c
-@@ -9,6 +9,8 @@
-  */
+Changes from v1: no changes in this patch
+
+ drivers/gpu/drm/rockchip/rockchip_drm_vop.h |  2 ++
+ drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 24 +++++++++++++++++++--
+ drivers/gpu/drm/rockchip/rockchip_vop_reg.h |  1 +
+ 3 files changed, 25 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+index 857d97cdc67c..14179e89bd21 100644
+--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+@@ -99,6 +99,8 @@ struct vop_common {
+       struct vop_reg dither_down_en;
+       struct vop_reg dither_up;
+       struct vop_reg dsp_lut_en;
++      struct vop_reg update_gamma_lut;
++      struct vop_reg lut_buffer_index;
+       struct vop_reg gate_en;
+       struct vop_reg mmu_en;
+       struct vop_reg out_mode;
+diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
+index ca7cc82125cb..bfb7e130f09b 100644
+--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
+@@ -865,6 +865,24 @@ static const struct vop_output rk3399_output = {
+       .mipi_dual_channel_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 3),
+ };
++static const struct vop_common rk3399_common = {
++      .standby = VOP_REG_SYNC(RK3399_SYS_CTRL, 0x1, 22),
++      .gate_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 23),
++      .mmu_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 20),
++      .dither_down_sel = VOP_REG(RK3399_DSP_CTRL1, 0x1, 4),
++      .dither_down_mode = VOP_REG(RK3399_DSP_CTRL1, 0x1, 3),
++      .dither_down_en = VOP_REG(RK3399_DSP_CTRL1, 0x1, 2),
++      .pre_dither_down = VOP_REG(RK3399_DSP_CTRL1, 0x1, 1),
++      .dither_up = VOP_REG(RK3399_DSP_CTRL1, 0x1, 6),
++      .dsp_lut_en = VOP_REG(RK3399_DSP_CTRL1, 0x1, 0),
++      .update_gamma_lut = VOP_REG(RK3399_DSP_CTRL1, 0x1, 7),
++      .lut_buffer_index = VOP_REG(RK3399_DBG_POST_REG1, 0x1, 1),
++      .data_blank = VOP_REG(RK3399_DSP_CTRL0, 0x1, 19),
++      .dsp_blank = VOP_REG(RK3399_DSP_CTRL0, 0x3, 18),
++      .out_mode = VOP_REG(RK3399_DSP_CTRL0, 0xf, 0),
++      .cfg_done = VOP_REG_SYNC(RK3399_REG_CFG_DONE, 0x1, 0),
++};
++
+ static const struct vop_yuv2yuv_phy rk3399_yuv2yuv_win01_data = {
+       .y2r_coefficients = {
+               VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 0, 0xffff, 0),
+@@ -944,7 +962,7 @@ static const struct vop_data rk3399_vop_big = {
+       .version = VOP_VERSION(3, 5),
+       .feature = VOP_FEATURE_OUTPUT_RGB10,
+       .intr = &rk3366_vop_intr,
+-      .common = &rk3288_common,
++      .common = &rk3399_common,
+       .modeset = &rk3288_modeset,
+       .output = &rk3399_output,
+       .afbc = &rk3399_vop_afbc,
+@@ -952,6 +970,7 @@ static const struct vop_data rk3399_vop_big = {
+       .win = rk3399_vop_win_data,
+       .win_size = ARRAY_SIZE(rk3399_vop_win_data),
+       .win_yuv2yuv = rk3399_vop_big_win_yuv2yuv_data,
++      .lut_size = 1024,
+ };
  
+ static const struct vop_win_data rk3399_vop_lit_win_data[] = {
+@@ -970,13 +989,14 @@ static const struct vop_win_yuv2yuv_data rk3399_vop_lit_win_yuv2yuv_data[] = {
+ static const struct vop_data rk3399_vop_lit = {
+       .version = VOP_VERSION(3, 6),
+       .intr = &rk3366_vop_intr,
+-      .common = &rk3288_common,
++      .common = &rk3399_common,
+       .modeset = &rk3288_modeset,
+       .output = &rk3399_output,
+       .misc = &rk3368_misc,
+       .win = rk3399_vop_lit_win_data,
+       .win_size = ARRAY_SIZE(rk3399_vop_lit_win_data),
+       .win_yuv2yuv = rk3399_vop_lit_win_yuv2yuv_data,
++      .lut_size = 256,
+ };
+ static const struct vop_win_data rk3228_vop_win_data[] = {
+diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h
+index 0b3cd65ba5c1..406e981c75bd 100644
+--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h
++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h
+@@ -628,6 +628,7 @@
+ #define RK3399_YUV2YUV_WIN                    0x02c0
+ #define RK3399_YUV2YUV_POST                   0x02c4
+ #define RK3399_AUTO_GATING_EN                 0x02cc
++#define RK3399_DBG_POST_REG1                  0x036c
+ #define RK3399_WIN0_CSC_COE                   0x03a0
+ #define RK3399_WIN1_CSC_COE                   0x03c0
+ #define RK3399_WIN2_CSC_COE                   0x03e0
+
+From: Hugh Cole-Baker <sigmaris@gmail.com>
+Subject: [PATCH v2 2/3] drm/rockchip: support gamma control on RK3399
+Date: Tue, 19 Oct 2021 22:58:42 +0100
+
+The RK3399 has a 1024-entry gamma LUT with 10 bits per component on its
+"big" VOP and a 256-entry, 8 bit per component LUT on the "little" VOP.
+Compared to the RK3288, it no longer requires disabling gamma while
+updating the LUT. On the RK3399, the LUT can be updated at any time as
+the hardware has two LUT buffers, one can be written while the other is
+in use. A swap of the buffers is triggered by writing 1 to the
+update_gamma_lut register.
+
+Signed-off-by: Hugh Cole-Baker <sigmaris@gmail.com>
+---
+
+Changes from v1: Moved the vop_crtc_gamma_set call to the end of
+vop_crtc_atomic_enable after the clocks and CRTC are enabled.
+
+ drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 105 +++++++++++++-------
+ 1 file changed, 71 insertions(+), 34 deletions(-)
+
+diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+index ba9e14da41b4..e2c97f1b26da 100644
+--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+@@ -9,6 +9,7 @@
  #include <linux/delay.h>
-+#include <linux/extcon.h>
-+#include <linux/extcon-provider.h>
- #include <linux/mutex.h>
+ #include <linux/iopoll.h>
+ #include <linux/kernel.h>
++#include <linux/log2.h>
  #include <linux/module.h>
- #include <linux/usb/pd_vdo.h>
-@@ -135,15 +137,53 @@ static int dp_altmode_status_update(struct dp_altmode *dp)
-       return ret;
+ #include <linux/of.h>
+ #include <linux/of_device.h>
+@@ -66,6 +67,9 @@
+ #define VOP_REG_SET(vop, group, name, v) \
+                   vop_reg_set(vop, &vop->data->group->name, 0, ~0, v, #name)
++#define VOP_HAS_REG(vop, group, name) \
++              (!!(vop->data->group->name.mask))
++
+ #define VOP_INTR_SET_TYPE(vop, name, type, v) \
+       do { \
+               int i, reg = 0, mask = 0; \
+@@ -1204,17 +1208,22 @@ static bool vop_dsp_lut_is_enabled(struct vop *vop)
+       return vop_read_reg(vop, 0, &vop->data->common->dsp_lut_en);
  }
  
-+static void dp_altmode_update_extcon(struct dp_altmode *dp, bool disconnect) {
-+      const struct device *dev = &dp->port->dev;
-+      struct extcon_dev* edev = NULL;
-+
-+      while (dev) {
-+              edev = extcon_find_edev_by_node(dev->of_node);
-+              if(!IS_ERR(edev)) {
-+                      break;
-+              }
-+              dev = dev->parent;
-+      }
-+
-+      if (IS_ERR_OR_NULL(edev)) {
-+              return;
-+      }
-+
-+      if (disconnect || !dp->data.conf) {
-+              extcon_set_state_sync(edev, EXTCON_DISP_DP, false);
-+      } else {
-+              union extcon_property_value extcon_true = { .intval = true };
-+              extcon_set_state(edev, EXTCON_DISP_DP, true);
-+              if (DP_CONF_GET_PIN_ASSIGN(dp->data.conf) & DP_PIN_ASSIGN_MULTI_FUNC_MASK) {
-+                      extcon_set_state_sync(edev, EXTCON_USB_HOST, true);
-+                      extcon_set_property(edev, EXTCON_DISP_DP, EXTCON_PROP_USB_SS,
-+                                               extcon_true);
-+              } else {
-+                      extcon_set_state_sync(edev, EXTCON_USB_HOST, false);
-+              }
-+              extcon_sync(edev, EXTCON_DISP_DP);
-+              extcon_set_state_sync(edev, EXTCON_USB, false);
-+      }
-+
++static u32 vop_lut_buffer_index(struct vop *vop)
++{
++      return vop_read_reg(vop, 0, &vop->data->common->lut_buffer_index);
 +}
 +
- static int dp_altmode_configured(struct dp_altmode *dp)
+ static void vop_crtc_write_gamma_lut(struct vop *vop, struct drm_crtc *crtc)
+ {
+       struct drm_color_lut *lut = crtc->state->gamma_lut->data;
+-      unsigned int i;
++      unsigned int i, bpc = ilog2(vop->data->lut_size);
+       for (i = 0; i < crtc->gamma_size; i++) {
+               u32 word;
+-              word = (drm_color_lut_extract(lut[i].red, 10) << 20) |
+-                     (drm_color_lut_extract(lut[i].green, 10) << 10) |
+-                      drm_color_lut_extract(lut[i].blue, 10);
++              word = (drm_color_lut_extract(lut[i].red, bpc) << (2 * bpc)) |
++                     (drm_color_lut_extract(lut[i].green, bpc) << bpc) |
++                      drm_color_lut_extract(lut[i].blue, bpc);
+               writel(word, vop->lut_regs + i * 4);
+       }
+ }
+@@ -1224,38 +1233,66 @@ static void vop_crtc_gamma_set(struct vop *vop, struct drm_crtc *crtc,
  {
+       struct drm_crtc_state *state = crtc->state;
+       unsigned int idle;
++      u32 lut_idx, old_idx;
        int ret;
  
-       sysfs_notify(&dp->alt->dev.kobj, "displayport", "configuration");
--      if (!dp->data.conf)
-+      if (!dp->data.conf) {
-+              dp_altmode_update_extcon(dp, true);
-               return typec_altmode_notify(dp->alt, TYPEC_STATE_USB,
-                                           &dp->data);
-+      }
+       if (!vop->lut_regs)
+               return;
+-      /*
+-       * To disable gamma (gamma_lut is null) or to write
+-       * an update to the LUT, clear dsp_lut_en.
+-       */
+-      spin_lock(&vop->reg_lock);
+-      VOP_REG_SET(vop, common, dsp_lut_en, 0);
+-      vop_cfg_done(vop);
+-      spin_unlock(&vop->reg_lock);
+-      /*
+-       * In order to write the LUT to the internal memory,
+-       * we need to first make sure the dsp_lut_en bit is cleared.
+-       */
+-      ret = readx_poll_timeout(vop_dsp_lut_is_enabled, vop,
+-                               idle, !idle, 5, 30 * 1000);
+-      if (ret) {
+-              DRM_DEV_ERROR(vop->dev, "display LUT RAM enable timeout!\n");
+-              return;
+-      }
++      if (!state->gamma_lut || !VOP_HAS_REG(vop, common, update_gamma_lut)) {
++              /*
++               * To disable gamma (gamma_lut is null) or to write
++               * an update to the LUT, clear dsp_lut_en.
++               */
++              spin_lock(&vop->reg_lock);
++              VOP_REG_SET(vop, common, dsp_lut_en, 0);
++              vop_cfg_done(vop);
++              spin_unlock(&vop->reg_lock);
+-      if (!state->gamma_lut)
+-              return;
++              /*
++               * In order to write the LUT to the internal memory,
++               * we need to first make sure the dsp_lut_en bit is cleared.
++               */
++              ret = readx_poll_timeout(vop_dsp_lut_is_enabled, vop,
++                                       idle, !idle, 5, 30 * 1000);
++              if (ret) {
++                      DRM_DEV_ERROR(vop->dev, "display LUT RAM enable timeout!\n");
++                      return;
++              }
 +
-+      dp_altmode_update_extcon(dp, false);
++              if (!state->gamma_lut)
++                      return;
++      } else {
++              /*
++               * On RK3399 the gamma LUT can updated without clearing dsp_lut_en,
++               * by setting update_gamma_lut then waiting for lut_buffer_index change
++               */
++              old_idx = vop_lut_buffer_index(vop);
++      }
  
-       ret = dp_altmode_notify(dp);
-       if (ret)
-@@ -170,9 +210,11 @@ static int dp_altmode_configure_vdm(struct dp_altmode *dp, u32 conf)
-       if (ret) {
-               if (DP_CONF_GET_PIN_ASSIGN(dp->data.conf))
-                       dp_altmode_notify(dp);
--              else
-+              else {
-+                      dp_altmode_update_extcon(dp, true);
-                       typec_altmode_notify(dp->alt, TYPEC_STATE_USB,
-                                            &dp->data);
+       spin_lock(&vop->reg_lock);
+       vop_crtc_write_gamma_lut(vop, crtc);
+       VOP_REG_SET(vop, common, dsp_lut_en, 1);
++      VOP_REG_SET(vop, common, update_gamma_lut, 1);
+       vop_cfg_done(vop);
+       spin_unlock(&vop->reg_lock);
++
++      if (VOP_HAS_REG(vop, common, update_gamma_lut)) {
++              ret = readx_poll_timeout(vop_lut_buffer_index, vop,
++                                       lut_idx, lut_idx != old_idx, 5, 30 * 1000);
++              if (ret) {
++                      DRM_DEV_ERROR(vop->dev, "gamma LUT update timeout!\n");
++                      return;
 +              }
-       }
-       return ret;
-@@ -211,6 +253,8 @@ static void dp_altmode_work(struct work_struct *work)
-       case DP_STATE_EXIT:
-               if (typec_altmode_exit(dp->alt))
-                       dev_err(&dp->alt->dev, "Exit Mode Failed!\n");
-+              else
-+                      dp_altmode_update_extcon(dp, true);
-               break;
-       default:
-               break;
-@@ -521,8 +565,13 @@ int dp_altmode_probe(struct typec_altmode *alt)
-       if (!(DP_CAP_DFP_D_PIN_ASSIGN(port->vdo) &
-             DP_CAP_UFP_D_PIN_ASSIGN(alt->vdo)) &&
-           !(DP_CAP_UFP_D_PIN_ASSIGN(port->vdo) &
--            DP_CAP_DFP_D_PIN_ASSIGN(alt->vdo)))
-+            DP_CAP_DFP_D_PIN_ASSIGN(alt->vdo))) {
-+              dev_err(&alt->dev, "No compatible pin configuration found:"\
-+                      "%04lx -> %04lx, %04lx <- %04lx",
-+                      DP_CAP_DFP_D_PIN_ASSIGN(port->vdo), DP_CAP_UFP_D_PIN_ASSIGN(alt->vdo),
-+                      DP_CAP_UFP_D_PIN_ASSIGN(port->vdo), DP_CAP_DFP_D_PIN_ASSIGN(alt->vdo));
-               return -ENODEV;
++
++              /*
++               * update_gamma_lut is auto cleared by HW, but write 0 to clear the bit
++               * in our backup of the regs.
++               */
++              spin_lock(&vop->reg_lock);
++              VOP_REG_SET(vop, common, update_gamma_lut, 0);
++              spin_unlock(&vop->reg_lock);
 +      }
+ }
  
-       ret = sysfs_create_group(&alt->dev.kobj, &dp_altmode_group);
-       if (ret)
--- 
-GitLab
-
-From e9d07cf5d983a3b941e604ae4ba9d277929e0650 Mon Sep 17 00:00:00 2001
-From: Tobias Schramm <t.schramm@manjaro.org>
-Date: Thu, 28 May 2020 14:34:47 +0200
-Subject: [PATCH] sound: soc: codecs: es8316: Run micdetect only if jack status
- asserted
-
-Think this is (was?) required to prevent flapping of detection status on
-the PBP.
-
-Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
----
- sound/soc/codecs/es8316.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
-index bd5d230c5df2..a2d8bf620b6f 100644
---- a/sound/soc/codecs/es8316.c
-+++ b/sound/soc/codecs/es8316.c
-@@ -688,7 +688,7 @@ static void es8316_disable_jack_detect(struct snd_soc_component *component)
-       snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE,
-                                     ES8316_GPIO_ENABLE_INTERRUPT, 0);
--      if (es8316->jack->status & SND_JACK_MICROPHONE) {
-+      if (es8316->jack && (es8316->jack->status & SND_JACK_MICROPHONE)) {
-               es8316_disable_micbias_for_mic_gnd_short_detect(component);
-               snd_soc_jack_report(es8316->jack, 0, SND_JACK_BTN_0);
+ static void vop_crtc_atomic_begin(struct drm_crtc *crtc,
+@@ -1305,14 +1342,6 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
+               return;
        }
--- 
-GitLab
-
-From edbf5d93dbd845faa4aa74fb8a7c5e76cf35ef0d Mon Sep 17 00:00:00 2001
-From: Tobias Schramm <t.schramm@manjaro.org>
-Date: Thu, 28 May 2020 14:36:47 +0200
-Subject: [PATCH] ASoC: soc-jack.c: supported inverted jack detect GPIOs
-
-Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
----
- sound/soc/soc-jack.c | 7 ++++---
- 1 file changed, 4 insertions(+), 3 deletions(-)
-
-diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
-index 0f1820f36b4d..8d9d77814f33 100644
---- a/sound/soc/soc-jack.c
-+++ b/sound/soc/soc-jack.c
-@@ -216,8 +216,6 @@ static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio)
-       int report;
-       enable = gpiod_get_value_cansleep(gpio->desc);
--      if (gpio->invert)
--              enable = !enable;
-       if (enable)
-               report = gpio->report;
-@@ -346,6 +344,9 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
-                               goto undo;
-                       }
-               } else {
-+                      int flags = GPIOF_IN;
-+                      if (gpios[i].invert)
-+                              flags |= GPIOF_ACTIVE_LOW;
-                       /* legacy GPIO number */
-                       if (!gpio_is_valid(gpios[i].gpio)) {
-                               dev_err(jack->card->dev,
-@@ -355,7 +356,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
-                               goto undo;
-                       }
  
--                      ret = gpio_request_one(gpios[i].gpio, GPIOF_IN,
-+                      ret = gpio_request_one(gpios[i].gpio, flags,
-                                              gpios[i].name);
-                       if (ret)
-                               goto undo;
--- 
-GitLab
-
-From 948d7ade0ddcf292b91d91cb8b6819a19ab3f604 Mon Sep 17 00:00:00 2001
-From: Tobias Schramm <t.schramm@manjaro.org>
-Date: Thu, 28 May 2020 14:44:15 +0200
-Subject: [PATCH] arm64: dts: rockchip: add typec extcon hack
-
-Not for mainline
-
-Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
----
- arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts | 5 +++++
- 1 file changed, 5 insertions(+)
-
-diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
-index decb212e2dca..37f967a89401 100644
---- a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
-+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
-@@ -401,6 +401,7 @@ opp08 {
+-      /*
+-       * If we have a GAMMA LUT in the state, then let's make sure
+-       * it's updated. We might be coming out of suspend,
+-       * which means the LUT internal memory needs to be re-written.
+-       */
+-      if (crtc->state->gamma_lut)
+-              vop_crtc_gamma_set(vop, crtc, old_state);
+-
+       mutex_lock(&vop->vop_lock);
  
- &cdn_dp {
-       status = "okay";
-+      extcon = <&fusb0>;
- };
+       WARN_ON(vop->event);
+@@ -1403,6 +1432,14 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
  
- &cpu_b0 {
-@@ -735,6 +736,9 @@ connector {
-                               <PDO_FIXED(5000, 1400, PDO_FIXED_USB_COMM)>;
-                       try-power-role = "sink";
-+                      extcon-cables = <1 2 5 6 9 10 12 44>;
-+                      typec-altmodes = <0xff01 1 0x001c0000 1>;
+       VOP_REG_SET(vop, common, standby, 0);
+       mutex_unlock(&vop->vop_lock);
 +
-                       ports {
-                               #address-cells = <1>;
-                               #size-cells = <0>;
-@@ -1002,6 +1006,7 @@ spiflash: flash@0 {
- };
++      /*
++       * If we have a GAMMA LUT in the state, then let's make sure
++       * it's updated. We might be coming out of suspend,
++       * which means the LUT internal memory needs to be re-written.
++       */
++      if (crtc->state->gamma_lut)
++              vop_crtc_gamma_set(vop, crtc, old_state);
+ }
  
- &tcphy0 {
-+      extcon = <&fusb0>;
-       status = "okay";
- };
+ static bool vop_fs_irq_is_pending(struct vop *vop)
+@@ -2125,8 +2162,8 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
  
--- 
-GitLab
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (res) {
+-              if (!vop_data->lut_size) {
+-                      DRM_DEV_ERROR(dev, "no gamma LUT size defined\n");
++              if (vop_data->lut_size != 1024 && vop_data->lut_size != 256) {
++                      DRM_DEV_ERROR(dev, "unsupported gamma LUT size %d\n", vop_data->lut_size);
+                       return -EINVAL;
+               }
+               vop->lut_regs = devm_ioremap_resource(dev, res);
 
-From a8f3e4ffe533f952a468cb8f3d067865bd58144f Mon Sep 17 00:00:00 2001
-From: Tobias Schramm <t.schramm@manjaro.org>
-Date: Sat, 6 Jun 2020 23:45:10 +0200
-Subject: [PATCH] arm64: dts: rockchip: setup USB type c port as dual data role
+From: Hugh Cole-Baker <sigmaris@gmail.com>
+Subject: [PATCH v2 3/3] arm64: dts: rockchip: enable gamma control on RK3399
+Date: Tue, 19 Oct 2021 22:58:43 +0100
 
-Some chargers try to put the charged device into device data role.
-Before this commit this condition caused the tcpm state machine to
-issue a hard reset due to a capability missmatch.
+Define the memory region on RK3399 VOPs containing the gamma LUT at
+base+0x2000.
 
-Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
+Signed-off-by: Hugh Cole-Baker <sigmaris@gmail.com>
 ---
- arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
-index c505c88b5d9b..d77dca5524ff 100644
---- a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
-+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
-@@ -726,7 +726,7 @@ fusb0: fusb30x@22 {
-               connector {
-                       compatible = "usb-c-connector";
--                      data-role = "host";
-+                      data-role = "dual";
-                       label = "USB-C";
-                       op-sink-microwatt = <1000000>;
-                       power-role = "dual";
--- 
-GitLab
 
+Changes from v1: no changes in this patch
+
+ arch/arm64/boot/dts/rockchip/rk3399.dtsi | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+index 3871c7fd83b0..9cbf6ccdd256 100644
+--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
++++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+@@ -1619,7 +1619,7 @@ i2s2: i2s@ff8a0000 {
+       vopl: vop@ff8f0000 {
+               compatible = "rockchip,rk3399-vop-lit";
+-              reg = <0x0 0xff8f0000 0x0 0x3efc>;
++              reg = <0x0 0xff8f0000 0x0 0x2000>, <0x0 0xff8f2000 0x0 0x400>;
+               interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH 0>;
+               assigned-clocks = <&cru ACLK_VOP1>, <&cru HCLK_VOP1>;
+               assigned-clock-rates = <400000000>, <100000000>;
+@@ -1676,7 +1676,7 @@ vopl_mmu: iommu@ff8f3f00 {
+       vopb: vop@ff900000 {
+               compatible = "rockchip,rk3399-vop-big";
+-              reg = <0x0 0xff900000 0x0 0x3efc>;
++              reg = <0x0 0xff900000 0x0 0x2000>, <0x0 0xff902000 0x0 0x1000>;
+               interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH 0>;
+               assigned-clocks = <&cru ACLK_VOP0>, <&cru HCLK_VOP0>;
+               assigned-clock-rates = <400000000>, <100000000>;
This page took 0.216482 seconds and 4 git commands to generate.