The one bugfix still applied cleanly. stable-dep-bot went a bit wild...
+++ /dev/null
-From 029d0d60ff3e472d06508b3d763218ed517f9a93 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 21 Sep 2021 11:06:17 -0700
-Subject: drm/bridge: parade-ps8640: Add support for AUX channel
-
-From: Philip Chen <philipchen@chromium.org>
-
-[ Upstream commit 13afcdd7277eff9ab5c92dc0d8d21335d132ab2f ]
-
-Implement the first version of AUX support, which will be useful as
-we expand the driver to support varied use cases.
-
-Signed-off-by: Philip Chen <philipchen@chromium.org>
-Reviewed-by: Sam Ravnborg <sam@ravnborg.org>
-Reviewed-by: Douglas Anderson <dianders@chromium.org>
-Reviewed-by: Stephen Boyd <swboyd@chromium.org>
-[dianders: whitespace fixes reported by dim apply-branch]
-Signed-off-by: Douglas Anderson <dianders@chromium.org>
-Link: https://patchwork.freedesktop.org/patch/msgid/20210921110556.v6.2.I1d6ea362dc76efa77cca2b46253d31b7651eaf17@changeid
-Stable-dep-of: fc94224c2e0a ("drm/bridge: parade-ps8640: Fix regulator supply order")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/gpu/drm/bridge/parade-ps8640.c | 180 ++++++++++++++++++++++++-
- 1 file changed, 179 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
-index 88c9f3404ac1..43afa848a36a 100644
---- a/drivers/gpu/drm/bridge/parade-ps8640.c
-+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
-@@ -13,11 +13,36 @@
- #include <linux/regulator/consumer.h>
-
- #include <drm/drm_bridge.h>
-+#include <drm/drm_dp_helper.h>
- #include <drm/drm_mipi_dsi.h>
- #include <drm/drm_of.h>
- #include <drm/drm_panel.h>
- #include <drm/drm_print.h>
-
-+#define PAGE0_AUXCH_CFG3 0x76
-+#define AUXCH_CFG3_RESET 0xff
-+#define PAGE0_SWAUX_ADDR_7_0 0x7d
-+#define PAGE0_SWAUX_ADDR_15_8 0x7e
-+#define PAGE0_SWAUX_ADDR_23_16 0x7f
-+#define SWAUX_ADDR_MASK GENMASK(19, 0)
-+#define PAGE0_SWAUX_LENGTH 0x80
-+#define SWAUX_LENGTH_MASK GENMASK(3, 0)
-+#define SWAUX_NO_PAYLOAD BIT(7)
-+#define PAGE0_SWAUX_WDATA 0x81
-+#define PAGE0_SWAUX_RDATA 0x82
-+#define PAGE0_SWAUX_CTRL 0x83
-+#define SWAUX_SEND BIT(0)
-+#define PAGE0_SWAUX_STATUS 0x84
-+#define SWAUX_M_MASK GENMASK(4, 0)
-+#define SWAUX_STATUS_MASK GENMASK(7, 5)
-+#define SWAUX_STATUS_NACK (0x1 << 5)
-+#define SWAUX_STATUS_DEFER (0x2 << 5)
-+#define SWAUX_STATUS_ACKM (0x3 << 5)
-+#define SWAUX_STATUS_INVALID (0x4 << 5)
-+#define SWAUX_STATUS_I2C_NACK (0x5 << 5)
-+#define SWAUX_STATUS_I2C_DEFER (0x6 << 5)
-+#define SWAUX_STATUS_TIMEOUT (0x7 << 5)
-+
- #define PAGE2_GPIO_H 0xa7
- #define PS_GPIO9 BIT(1)
- #define PAGE2_I2C_BYPASS 0xea
-@@ -66,6 +91,7 @@ enum ps8640_vdo_control {
- struct ps8640 {
- struct drm_bridge bridge;
- struct drm_bridge *panel_bridge;
-+ struct drm_dp_aux aux;
- struct mipi_dsi_device *dsi;
- struct i2c_client *page[MAX_DEVS];
- struct regmap *regmap[MAX_DEVS];
-@@ -115,6 +141,137 @@ static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e)
- return container_of(e, struct ps8640, bridge);
- }
-
-+static inline struct ps8640 *aux_to_ps8640(struct drm_dp_aux *aux)
-+{
-+ return container_of(aux, struct ps8640, aux);
-+}
-+
-+static ssize_t ps8640_aux_transfer(struct drm_dp_aux *aux,
-+ struct drm_dp_aux_msg *msg)
-+{
-+ struct ps8640 *ps_bridge = aux_to_ps8640(aux);
-+ struct regmap *map = ps_bridge->regmap[PAGE0_DP_CNTL];
-+ struct device *dev = &ps_bridge->page[PAGE0_DP_CNTL]->dev;
-+ unsigned int len = msg->size;
-+ unsigned int data;
-+ unsigned int base;
-+ int ret;
-+ u8 request = msg->request &
-+ ~(DP_AUX_I2C_MOT | DP_AUX_I2C_WRITE_STATUS_UPDATE);
-+ u8 *buf = msg->buffer;
-+ u8 addr_len[PAGE0_SWAUX_LENGTH + 1 - PAGE0_SWAUX_ADDR_7_0];
-+ u8 i;
-+ bool is_native_aux = false;
-+
-+ if (len > DP_AUX_MAX_PAYLOAD_BYTES)
-+ return -EINVAL;
-+
-+ if (msg->address & ~SWAUX_ADDR_MASK)
-+ return -EINVAL;
-+
-+ switch (request) {
-+ case DP_AUX_NATIVE_WRITE:
-+ case DP_AUX_NATIVE_READ:
-+ is_native_aux = true;
-+ fallthrough;
-+ case DP_AUX_I2C_WRITE:
-+ case DP_AUX_I2C_READ:
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ ret = regmap_write(map, PAGE0_AUXCH_CFG3, AUXCH_CFG3_RESET);
-+ if (ret) {
-+ DRM_DEV_ERROR(dev, "failed to write PAGE0_AUXCH_CFG3: %d\n",
-+ ret);
-+ return ret;
-+ }
-+
-+ /* Assume it's good */
-+ msg->reply = 0;
-+
-+ base = PAGE0_SWAUX_ADDR_7_0;
-+ addr_len[PAGE0_SWAUX_ADDR_7_0 - base] = msg->address;
-+ addr_len[PAGE0_SWAUX_ADDR_15_8 - base] = msg->address >> 8;
-+ addr_len[PAGE0_SWAUX_ADDR_23_16 - base] = (msg->address >> 16) |
-+ (msg->request << 4);
-+ addr_len[PAGE0_SWAUX_LENGTH - base] = (len == 0) ? SWAUX_NO_PAYLOAD :
-+ ((len - 1) & SWAUX_LENGTH_MASK);
-+
-+ regmap_bulk_write(map, PAGE0_SWAUX_ADDR_7_0, addr_len,
-+ ARRAY_SIZE(addr_len));
-+
-+ if (len && (request == DP_AUX_NATIVE_WRITE ||
-+ request == DP_AUX_I2C_WRITE)) {
-+ /* Write to the internal FIFO buffer */
-+ for (i = 0; i < len; i++) {
-+ ret = regmap_write(map, PAGE0_SWAUX_WDATA, buf[i]);
-+ if (ret) {
-+ DRM_DEV_ERROR(dev,
-+ "failed to write WDATA: %d\n",
-+ ret);
-+ return ret;
-+ }
-+ }
-+ }
-+
-+ regmap_write(map, PAGE0_SWAUX_CTRL, SWAUX_SEND);
-+
-+ /* Zero delay loop because i2c transactions are slow already */
-+ regmap_read_poll_timeout(map, PAGE0_SWAUX_CTRL, data,
-+ !(data & SWAUX_SEND), 0, 50 * 1000);
-+
-+ regmap_read(map, PAGE0_SWAUX_STATUS, &data);
-+ if (ret) {
-+ DRM_DEV_ERROR(dev, "failed to read PAGE0_SWAUX_STATUS: %d\n",
-+ ret);
-+ return ret;
-+ }
-+
-+ switch (data & SWAUX_STATUS_MASK) {
-+ /* Ignore the DEFER cases as they are already handled in hardware */
-+ case SWAUX_STATUS_NACK:
-+ case SWAUX_STATUS_I2C_NACK:
-+ /*
-+ * The programming guide is not clear about whether a I2C NACK
-+ * would trigger SWAUX_STATUS_NACK or SWAUX_STATUS_I2C_NACK. So
-+ * we handle both cases together.
-+ */
-+ if (is_native_aux)
-+ msg->reply |= DP_AUX_NATIVE_REPLY_NACK;
-+ else
-+ msg->reply |= DP_AUX_I2C_REPLY_NACK;
-+
-+ fallthrough;
-+ case SWAUX_STATUS_ACKM:
-+ len = data & SWAUX_M_MASK;
-+ break;
-+ case SWAUX_STATUS_INVALID:
-+ return -EOPNOTSUPP;
-+ case SWAUX_STATUS_TIMEOUT:
-+ return -ETIMEDOUT;
-+ }
-+
-+ if (len && (request == DP_AUX_NATIVE_READ ||
-+ request == DP_AUX_I2C_READ)) {
-+ /* Read from the internal FIFO buffer */
-+ for (i = 0; i < len; i++) {
-+ ret = regmap_read(map, PAGE0_SWAUX_RDATA, &data);
-+ if (ret) {
-+ DRM_DEV_ERROR(dev,
-+ "failed to read RDATA: %d\n",
-+ ret);
-+ return ret;
-+ }
-+
-+ buf[i] = data;
-+ }
-+ }
-+
-+ return len;
-+}
-+
- static int ps8640_bridge_vdo_control(struct ps8640 *ps_bridge,
- const enum ps8640_vdo_control ctrl)
- {
-@@ -284,18 +441,33 @@ static int ps8640_bridge_attach(struct drm_bridge *bridge,
- dsi->format = MIPI_DSI_FMT_RGB888;
- dsi->lanes = DP_NUM_LANES;
- ret = mipi_dsi_attach(dsi);
-- if (ret)
-+ if (ret) {
-+ dev_err(dev, "failed to attach dsi device: %d\n", ret);
- goto err_dsi_attach;
-+ }
-+
-+ ret = drm_dp_aux_register(&ps_bridge->aux);
-+ if (ret) {
-+ dev_err(dev, "failed to register DP AUX channel: %d\n", ret);
-+ goto err_aux_register;
-+ }
-
- /* Attach the panel-bridge to the dsi bridge */
- return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge,
- &ps_bridge->bridge, flags);
-
-+err_aux_register:
-+ mipi_dsi_detach(dsi);
- err_dsi_attach:
- mipi_dsi_device_unregister(dsi);
- return ret;
- }
-
-+static void ps8640_bridge_detach(struct drm_bridge *bridge)
-+{
-+ drm_dp_aux_unregister(&bridge_to_ps8640(bridge)->aux);
-+}
-+
- static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge,
- struct drm_connector *connector)
- {
-@@ -332,6 +504,7 @@ static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge,
-
- static const struct drm_bridge_funcs ps8640_bridge_funcs = {
- .attach = ps8640_bridge_attach,
-+ .detach = ps8640_bridge_detach,
- .get_edid = ps8640_bridge_get_edid,
- .post_disable = ps8640_post_disable,
- .pre_enable = ps8640_pre_enable,
-@@ -407,6 +580,11 @@ static int ps8640_probe(struct i2c_client *client)
-
- i2c_set_clientdata(client, ps_bridge);
-
-+ ps_bridge->aux.name = "parade-ps8640-aux";
-+ ps_bridge->aux.dev = dev;
-+ ps_bridge->aux.transfer = ps8640_aux_transfer;
-+ drm_dp_aux_init(&ps_bridge->aux);
-+
- drm_bridge_add(&ps_bridge->bridge);
-
- return 0;
---
-2.35.1
-
+++ /dev/null
-From 6748190b8ca2e4190e17651940875380113e8cad Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 28 Oct 2021 10:58:10 -0700
-Subject: drm/bridge: parade-ps8640: Enable runtime power management
-
-From: Philip Chen <philipchen@chromium.org>
-
-[ Upstream commit 826cff3f7ebba460d3db61f135798ce76b0d26ed ]
-
-Fit ps8640 driver into runtime power management framework:
-
-First, break _poweron() to 3 parts: (1) turn on power and wait for
-ps8640's internal MCU to finish init (2) check panel HPD (which is
-proxied by GPIO9) (3) the other configs. As runtime_resume() can be
-called before panel is powered, we only add (1) to _resume() and leave
-(2)(3) to _pre_enable(). We also add (2) to _aux_transfer() as we want
-to ensure panel HPD is asserted before we start AUX CH transactions.
-
-Second, the original driver has a mysterious delay of 50 ms between (2)
-and (3). Since Parade's support can't explain what the delay is for,
-and we don't see removing the delay break any boards at hand, remove
-the delay to fit into this driver change.
-
-In addition, rename "powered" to "pre_enabled" and don't check for it
-in the pm_runtime calls. The pm_runtime calls are already refcounted
-so there's no reason to check there. The other user of "powered",
-_get_edid(), only cares if pre_enable() has already been called.
-
-Lastly, change some existing DRM_...() logging to dev_...() along the
-way, since DRM_...() seem to be deprecated in [1].
-
-[1] https://patchwork.freedesktop.org/patch/454760/
-
-Signed-off-by: Philip Chen <philipchen@chromium.org>
-Reviewed-by: Douglas Anderson <dianders@chromium.org>
-Reviewed-by: Stephen Boyd <swboyd@chromium.org>
-[dianders: fixed whitespace warning reported by dim tool]
-Signed-off-by: Douglas Anderson <dianders@chromium.org>
-Link: https://patchwork.freedesktop.org/patch/msgid/20211028105754.v5.1.I828f5db745535fb7e36e8ffdd62d546f6d08b6d1@changeid
-Stable-dep-of: fc94224c2e0a ("drm/bridge: parade-ps8640: Fix regulator supply order")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/gpu/drm/bridge/parade-ps8640.c | 190 ++++++++++++++++---------
- 1 file changed, 119 insertions(+), 71 deletions(-)
-
-diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
-index 43afa848a36a..52f2ea6fcb26 100644
---- a/drivers/gpu/drm/bridge/parade-ps8640.c
-+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
-@@ -9,6 +9,7 @@
- #include <linux/i2c.h>
- #include <linux/module.h>
- #include <linux/of_graph.h>
-+#include <linux/pm_runtime.h>
- #include <linux/regmap.h>
- #include <linux/regulator/consumer.h>
-
-@@ -98,7 +99,7 @@ struct ps8640 {
- struct regulator_bulk_data supplies[2];
- struct gpio_desc *gpio_reset;
- struct gpio_desc *gpio_powerdown;
-- bool powered;
-+ bool pre_enabled;
- };
-
- static const struct regmap_config ps8640_regmap_config[] = {
-@@ -146,8 +147,29 @@ static inline struct ps8640 *aux_to_ps8640(struct drm_dp_aux *aux)
- return container_of(aux, struct ps8640, aux);
- }
-
--static ssize_t ps8640_aux_transfer(struct drm_dp_aux *aux,
-- struct drm_dp_aux_msg *msg)
-+static int ps8640_ensure_hpd(struct ps8640 *ps_bridge)
-+{
-+ struct regmap *map = ps_bridge->regmap[PAGE2_TOP_CNTL];
-+ struct device *dev = &ps_bridge->page[PAGE2_TOP_CNTL]->dev;
-+ int status;
-+ int ret;
-+
-+ /*
-+ * Apparently something about the firmware in the chip signals that
-+ * HPD goes high by reporting GPIO9 as high (even though HPD isn't
-+ * actually connected to GPIO9).
-+ */
-+ ret = regmap_read_poll_timeout(map, PAGE2_GPIO_H, status,
-+ status & PS_GPIO9, 20 * 1000, 200 * 1000);
-+
-+ if (ret < 0)
-+ dev_warn(dev, "HPD didn't go high: %d\n", ret);
-+
-+ return ret;
-+}
-+
-+static ssize_t ps8640_aux_transfer_msg(struct drm_dp_aux *aux,
-+ struct drm_dp_aux_msg *msg)
- {
- struct ps8640 *ps_bridge = aux_to_ps8640(aux);
- struct regmap *map = ps_bridge->regmap[PAGE0_DP_CNTL];
-@@ -272,38 +294,49 @@ static ssize_t ps8640_aux_transfer(struct drm_dp_aux *aux,
- return len;
- }
-
--static int ps8640_bridge_vdo_control(struct ps8640 *ps_bridge,
-- const enum ps8640_vdo_control ctrl)
-+static ssize_t ps8640_aux_transfer(struct drm_dp_aux *aux,
-+ struct drm_dp_aux_msg *msg)
-+{
-+ struct ps8640 *ps_bridge = aux_to_ps8640(aux);
-+ struct device *dev = &ps_bridge->page[PAGE0_DP_CNTL]->dev;
-+ int ret;
-+
-+ pm_runtime_get_sync(dev);
-+ ret = ps8640_ensure_hpd(ps_bridge);
-+ if (!ret)
-+ ret = ps8640_aux_transfer_msg(aux, msg);
-+ pm_runtime_mark_last_busy(dev);
-+ pm_runtime_put_autosuspend(dev);
-+
-+ return ret;
-+}
-+
-+static void ps8640_bridge_vdo_control(struct ps8640 *ps_bridge,
-+ const enum ps8640_vdo_control ctrl)
- {
- struct regmap *map = ps_bridge->regmap[PAGE3_DSI_CNTL1];
-+ struct device *dev = &ps_bridge->page[PAGE3_DSI_CNTL1]->dev;
- u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, ctrl };
- int ret;
-
- ret = regmap_bulk_write(map, PAGE3_SET_ADD,
- vdo_ctrl_buf, sizeof(vdo_ctrl_buf));
-
-- if (ret < 0) {
-- DRM_ERROR("failed to %sable VDO: %d\n",
-- ctrl == ENABLE ? "en" : "dis", ret);
-- return ret;
-- }
--
-- return 0;
-+ if (ret < 0)
-+ dev_err(dev, "failed to %sable VDO: %d\n",
-+ ctrl == ENABLE ? "en" : "dis", ret);
- }
-
--static void ps8640_bridge_poweron(struct ps8640 *ps_bridge)
-+static int __maybe_unused ps8640_resume(struct device *dev)
- {
-- struct regmap *map = ps_bridge->regmap[PAGE2_TOP_CNTL];
-- int ret, status;
--
-- if (ps_bridge->powered)
-- return;
-+ struct ps8640 *ps_bridge = dev_get_drvdata(dev);
-+ int ret;
-
- ret = regulator_bulk_enable(ARRAY_SIZE(ps_bridge->supplies),
- ps_bridge->supplies);
- if (ret < 0) {
-- DRM_ERROR("cannot enable regulators %d\n", ret);
-- return;
-+ dev_err(dev, "cannot enable regulators %d\n", ret);
-+ return ret;
- }
-
- gpiod_set_value(ps_bridge->gpio_powerdown, 0);
-@@ -312,86 +345,78 @@ static void ps8640_bridge_poweron(struct ps8640 *ps_bridge)
- gpiod_set_value(ps_bridge->gpio_reset, 0);
-
- /*
-- * Wait for the ps8640 embedded MCU to be ready
-- * First wait 200ms and then check the MCU ready flag every 20ms
-+ * Mystery 200 ms delay for the "MCU to be ready". It's unclear if
-+ * this is truly necessary since the MCU will already signal that
-+ * things are "good to go" by signaling HPD on "gpio 9". See
-+ * ps8640_ensure_hpd(). For now we'll keep this mystery delay just in
-+ * case.
- */
- msleep(200);
-
-- ret = regmap_read_poll_timeout(map, PAGE2_GPIO_H, status,
-- status & PS_GPIO9, 20 * 1000, 200 * 1000);
--
-- if (ret < 0) {
-- DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", ret);
-- goto err_regulators_disable;
-- }
--
-- msleep(50);
--
-- /*
-- * The Manufacturer Command Set (MCS) is a device dependent interface
-- * intended for factory programming of the display module default
-- * parameters. Once the display module is configured, the MCS shall be
-- * disabled by the manufacturer. Once disabled, all MCS commands are
-- * ignored by the display interface.
-- */
--
-- ret = regmap_update_bits(map, PAGE2_MCS_EN, MCS_EN, 0);
-- if (ret < 0) {
-- DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
-- goto err_regulators_disable;
-- }
--
-- /* Switch access edp panel's edid through i2c */
-- ret = regmap_write(map, PAGE2_I2C_BYPASS, I2C_BYPASS_EN);
-- if (ret < 0) {
-- DRM_ERROR("failed write PAGE2_I2C_BYPASS: %d\n", ret);
-- goto err_regulators_disable;
-- }
--
-- ps_bridge->powered = true;
--
-- return;
--
--err_regulators_disable:
-- regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
-- ps_bridge->supplies);
-+ return 0;
- }
-
--static void ps8640_bridge_poweroff(struct ps8640 *ps_bridge)
-+static int __maybe_unused ps8640_suspend(struct device *dev)
- {
-+ struct ps8640 *ps_bridge = dev_get_drvdata(dev);
- int ret;
-
-- if (!ps_bridge->powered)
-- return;
--
- gpiod_set_value(ps_bridge->gpio_reset, 1);
- gpiod_set_value(ps_bridge->gpio_powerdown, 1);
- ret = regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
- ps_bridge->supplies);
- if (ret < 0)
-- DRM_ERROR("cannot disable regulators %d\n", ret);
-+ dev_err(dev, "cannot disable regulators %d\n", ret);
-
-- ps_bridge->powered = false;
-+ return ret;
- }
-
-+static const struct dev_pm_ops ps8640_pm_ops = {
-+ SET_RUNTIME_PM_OPS(ps8640_suspend, ps8640_resume, NULL)
-+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-+ pm_runtime_force_resume)
-+};
-+
- static void ps8640_pre_enable(struct drm_bridge *bridge)
- {
- struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
-+ struct regmap *map = ps_bridge->regmap[PAGE2_TOP_CNTL];
-+ struct device *dev = &ps_bridge->page[PAGE0_DP_CNTL]->dev;
- int ret;
-
-- ps8640_bridge_poweron(ps_bridge);
-+ pm_runtime_get_sync(dev);
-+ ps8640_ensure_hpd(ps_bridge);
-
-- ret = ps8640_bridge_vdo_control(ps_bridge, ENABLE);
-+ /*
-+ * The Manufacturer Command Set (MCS) is a device dependent interface
-+ * intended for factory programming of the display module default
-+ * parameters. Once the display module is configured, the MCS shall be
-+ * disabled by the manufacturer. Once disabled, all MCS commands are
-+ * ignored by the display interface.
-+ */
-+
-+ ret = regmap_update_bits(map, PAGE2_MCS_EN, MCS_EN, 0);
-+ if (ret < 0)
-+ dev_warn(dev, "failed write PAGE2_MCS_EN: %d\n", ret);
-+
-+ /* Switch access edp panel's edid through i2c */
-+ ret = regmap_write(map, PAGE2_I2C_BYPASS, I2C_BYPASS_EN);
- if (ret < 0)
-- ps8640_bridge_poweroff(ps_bridge);
-+ dev_warn(dev, "failed write PAGE2_MCS_EN: %d\n", ret);
-+
-+ ps8640_bridge_vdo_control(ps_bridge, ENABLE);
-+
-+ ps_bridge->pre_enabled = true;
- }
-
- static void ps8640_post_disable(struct drm_bridge *bridge)
- {
- struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
-
-+ ps_bridge->pre_enabled = false;
-+
- ps8640_bridge_vdo_control(ps_bridge, DISABLE);
-- ps8640_bridge_poweroff(ps_bridge);
-+ pm_runtime_put_sync_suspend(&ps_bridge->page[PAGE0_DP_CNTL]->dev);
- }
-
- static int ps8640_bridge_attach(struct drm_bridge *bridge,
-@@ -472,7 +497,7 @@ static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge,
- struct drm_connector *connector)
- {
- struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
-- bool poweroff = !ps_bridge->powered;
-+ bool poweroff = !ps_bridge->pre_enabled;
- struct edid *edid;
-
- /*
-@@ -502,6 +527,12 @@ static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge,
- return edid;
- }
-
-+static void ps8640_runtime_disable(void *data)
-+{
-+ pm_runtime_dont_use_autosuspend(data);
-+ pm_runtime_disable(data);
-+}
-+
- static const struct drm_bridge_funcs ps8640_bridge_funcs = {
- .attach = ps8640_bridge_attach,
- .detach = ps8640_bridge_detach,
-@@ -585,6 +616,22 @@ static int ps8640_probe(struct i2c_client *client)
- ps_bridge->aux.transfer = ps8640_aux_transfer;
- drm_dp_aux_init(&ps_bridge->aux);
-
-+ pm_runtime_enable(dev);
-+ /*
-+ * Powering on ps8640 takes ~300ms. To avoid wasting time on power
-+ * cycling ps8640 too often, set autosuspend_delay to 500ms to ensure
-+ * the bridge wouldn't suspend in between each _aux_transfer_msg() call
-+ * during EDID read (~20ms in my experiment) and in between the last
-+ * _aux_transfer_msg() call during EDID read and the _pre_enable() call
-+ * (~100ms in my experiment).
-+ */
-+ pm_runtime_set_autosuspend_delay(dev, 500);
-+ pm_runtime_use_autosuspend(dev);
-+ pm_suspend_ignore_children(dev, true);
-+ ret = devm_add_action_or_reset(dev, ps8640_runtime_disable, dev);
-+ if (ret)
-+ return ret;
-+
- drm_bridge_add(&ps_bridge->bridge);
-
- return 0;
-@@ -611,6 +658,7 @@ static struct i2c_driver ps8640_driver = {
- .driver = {
- .name = "ps8640",
- .of_match_table = ps8640_match,
-+ .pm = &ps8640_pm_ops,
- },
- };
- module_i2c_driver(ps8640_driver);
---
-2.35.1
-
Signed-off-by: Robert Foss <robert.foss@linaro.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20220721092258.3397461-1-wenst@chromium.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
- drivers/gpu/drm/bridge/parade-ps8640.c | 4 ++--
+ drivers/gpu/drm/bridge/parade-ps8640.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
-diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
-index 52f2ea6fcb26..1367cc2d6fd7 100644
--- a/drivers/gpu/drm/bridge/parade-ps8640.c
+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
-@@ -565,8 +565,8 @@ static int ps8640_probe(struct i2c_client *client)
+@@ -333,8 +333,8 @@ static int ps8640_probe(struct i2c_clien
if (IS_ERR(ps_bridge->panel_bridge))
return PTR_ERR(ps_bridge->panel_bridge);
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies),
ps_bridge->supplies);
if (ret)
---
-2.35.1
-
+++ /dev/null
-From af54466e5b4eef355f8fee40de437401e6f8381a Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 21 Sep 2021 11:06:16 -0700
-Subject: drm/bridge: parade-ps8640: Use regmap APIs
-
-From: Philip Chen <philipchen@chromium.org>
-
-[ Upstream commit 692d8db0a5ca123017d7d4847856343512f87af9 ]
-
-Replace the direct i2c access (i2c_smbus_* functions) with regmap APIs,
-which will simplify the future update on ps8640 driver.
-
-Signed-off-by: Philip Chen <philipchen@chromium.org>
-Reviewed-by: Douglas Anderson <dianders@chromium.org>
-Acked-by: Sam Ravnborg <sam@ravnborg.org>
-Reviewed-by: Stephen Boyd <swboyd@chromium.org>
-[dianders: whitespace fixes reported by dim apply-branch]
-Signed-off-by: Douglas Anderson <dianders@chromium.org>
-Link: https://patchwork.freedesktop.org/patch/msgid/20210921110556.v6.1.I2351df94f18d5d8debc22d4d100f36fac560409a@changeid
-Stable-dep-of: fc94224c2e0a ("drm/bridge: parade-ps8640: Fix regulator supply order")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/gpu/drm/bridge/parade-ps8640.c | 94 ++++++++++++++++++--------
- 1 file changed, 64 insertions(+), 30 deletions(-)
-
-diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
-index 7bd0affa057a..88c9f3404ac1 100644
---- a/drivers/gpu/drm/bridge/parade-ps8640.c
-+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
-@@ -9,6 +9,7 @@
- #include <linux/i2c.h>
- #include <linux/module.h>
- #include <linux/of_graph.h>
-+#include <linux/regmap.h>
- #include <linux/regulator/consumer.h>
-
- #include <drm/drm_bridge.h>
-@@ -29,6 +30,11 @@
- #define VDO_EN 0x1c
- #define DP_NUM_LANES 4
-
-+#define COMMON_PS8640_REGMAP_CONFIG \
-+ .reg_bits = 8, \
-+ .val_bits = 8, \
-+ .cache_type = REGCACHE_NONE
-+
- /*
- * PS8640 uses multiple addresses:
- * page[0]: for DP control
-@@ -62,12 +68,48 @@ struct ps8640 {
- struct drm_bridge *panel_bridge;
- struct mipi_dsi_device *dsi;
- struct i2c_client *page[MAX_DEVS];
-+ struct regmap *regmap[MAX_DEVS];
- struct regulator_bulk_data supplies[2];
- struct gpio_desc *gpio_reset;
- struct gpio_desc *gpio_powerdown;
- bool powered;
- };
-
-+static const struct regmap_config ps8640_regmap_config[] = {
-+ [PAGE0_DP_CNTL] = {
-+ COMMON_PS8640_REGMAP_CONFIG,
-+ .max_register = 0xbf,
-+ },
-+ [PAGE1_VDO_BDG] = {
-+ COMMON_PS8640_REGMAP_CONFIG,
-+ .max_register = 0xff,
-+ },
-+ [PAGE2_TOP_CNTL] = {
-+ COMMON_PS8640_REGMAP_CONFIG,
-+ .max_register = 0xff,
-+ },
-+ [PAGE3_DSI_CNTL1] = {
-+ COMMON_PS8640_REGMAP_CONFIG,
-+ .max_register = 0xff,
-+ },
-+ [PAGE4_MIPI_PHY] = {
-+ COMMON_PS8640_REGMAP_CONFIG,
-+ .max_register = 0xff,
-+ },
-+ [PAGE5_VPLL] = {
-+ COMMON_PS8640_REGMAP_CONFIG,
-+ .max_register = 0x7f,
-+ },
-+ [PAGE6_DSI_CNTL2] = {
-+ COMMON_PS8640_REGMAP_CONFIG,
-+ .max_register = 0xff,
-+ },
-+ [PAGE7_SPI_CNTL] = {
-+ COMMON_PS8640_REGMAP_CONFIG,
-+ .max_register = 0xff,
-+ },
-+};
-+
- static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e)
- {
- return container_of(e, struct ps8640, bridge);
-@@ -76,13 +118,13 @@ static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e)
- static int ps8640_bridge_vdo_control(struct ps8640 *ps_bridge,
- const enum ps8640_vdo_control ctrl)
- {
-- struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
-+ struct regmap *map = ps_bridge->regmap[PAGE3_DSI_CNTL1];
- u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, ctrl };
- int ret;
-
-- ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
-- sizeof(vdo_ctrl_buf),
-- vdo_ctrl_buf);
-+ ret = regmap_bulk_write(map, PAGE3_SET_ADD,
-+ vdo_ctrl_buf, sizeof(vdo_ctrl_buf));
-+
- if (ret < 0) {
- DRM_ERROR("failed to %sable VDO: %d\n",
- ctrl == ENABLE ? "en" : "dis", ret);
-@@ -94,8 +136,7 @@ static int ps8640_bridge_vdo_control(struct ps8640 *ps_bridge,
-
- static void ps8640_bridge_poweron(struct ps8640 *ps_bridge)
- {
-- struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL];
-- unsigned long timeout;
-+ struct regmap *map = ps_bridge->regmap[PAGE2_TOP_CNTL];
- int ret, status;
-
- if (ps_bridge->powered)
-@@ -119,18 +160,12 @@ static void ps8640_bridge_poweron(struct ps8640 *ps_bridge)
- */
- msleep(200);
-
-- timeout = jiffies + msecs_to_jiffies(200) + 1;
--
-- while (time_is_after_jiffies(timeout)) {
-- status = i2c_smbus_read_byte_data(client, PAGE2_GPIO_H);
-- if (status < 0) {
-- DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", status);
-- goto err_regulators_disable;
-- }
-- if ((status & PS_GPIO9) == PS_GPIO9)
-- break;
-+ ret = regmap_read_poll_timeout(map, PAGE2_GPIO_H, status,
-+ status & PS_GPIO9, 20 * 1000, 200 * 1000);
-
-- msleep(20);
-+ if (ret < 0) {
-+ DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", ret);
-+ goto err_regulators_disable;
- }
-
- msleep(50);
-@@ -142,22 +177,15 @@ static void ps8640_bridge_poweron(struct ps8640 *ps_bridge)
- * disabled by the manufacturer. Once disabled, all MCS commands are
- * ignored by the display interface.
- */
-- status = i2c_smbus_read_byte_data(client, PAGE2_MCS_EN);
-- if (status < 0) {
-- DRM_ERROR("failed read PAGE2_MCS_EN: %d\n", status);
-- goto err_regulators_disable;
-- }
-
-- ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN,
-- status & ~MCS_EN);
-+ ret = regmap_update_bits(map, PAGE2_MCS_EN, MCS_EN, 0);
- if (ret < 0) {
- DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
- goto err_regulators_disable;
- }
-
- /* Switch access edp panel's edid through i2c */
-- ret = i2c_smbus_write_byte_data(client, PAGE2_I2C_BYPASS,
-- I2C_BYPASS_EN);
-+ ret = regmap_write(map, PAGE2_I2C_BYPASS, I2C_BYPASS_EN);
- if (ret < 0) {
- DRM_ERROR("failed write PAGE2_I2C_BYPASS: %d\n", ret);
- goto err_regulators_disable;
-@@ -360,15 +388,21 @@ static int ps8640_probe(struct i2c_client *client)
-
- ps_bridge->page[PAGE0_DP_CNTL] = client;
-
-+ ps_bridge->regmap[PAGE0_DP_CNTL] = devm_regmap_init_i2c(client, ps8640_regmap_config);
-+ if (IS_ERR(ps_bridge->regmap[PAGE0_DP_CNTL]))
-+ return PTR_ERR(ps_bridge->regmap[PAGE0_DP_CNTL]);
-+
- for (i = 1; i < ARRAY_SIZE(ps_bridge->page); i++) {
- ps_bridge->page[i] = devm_i2c_new_dummy_device(&client->dev,
- client->adapter,
- client->addr + i);
-- if (IS_ERR(ps_bridge->page[i])) {
-- dev_err(dev, "failed i2c dummy device, address %02x\n",
-- client->addr + i);
-+ if (IS_ERR(ps_bridge->page[i]))
- return PTR_ERR(ps_bridge->page[i]);
-- }
-+
-+ ps_bridge->regmap[i] = devm_regmap_init_i2c(ps_bridge->page[i],
-+ ps8640_regmap_config + i);
-+ if (IS_ERR(ps_bridge->regmap[i]))
-+ return PTR_ERR(ps_bridge->regmap[i]);
- }
-
- i2c_set_clientdata(client, ps_bridge);
---
-2.35.1
-
drm-bridge-adv7511-fix-cec-power-down-control-regist.patch
drm-bridge-avoid-uninitialized-variable-warning.patch
drm-mipi-dsi-detach-devices-when-removing-the-host.patch
-drm-bridge-parade-ps8640-use-regmap-apis.patch
-drm-bridge-parade-ps8640-add-support-for-aux-channel.patch
-drm-bridge-parade-ps8640-enable-runtime-power-manage.patch
drm-bridge-parade-ps8640-fix-regulator-supply-order.patch
net-wwan-t7xx-add-control-dma-interface.patch
drm-dp_mst-fix-drm_dp_dpcd_read-return-value-checks.patch
+++ /dev/null
-From 2d9eb1483129ca84e2f02222ef920c57bf86b378 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 21 Sep 2021 11:06:17 -0700
-Subject: drm/bridge: parade-ps8640: Add support for AUX channel
-
-From: Philip Chen <philipchen@chromium.org>
-
-[ Upstream commit 13afcdd7277eff9ab5c92dc0d8d21335d132ab2f ]
-
-Implement the first version of AUX support, which will be useful as
-we expand the driver to support varied use cases.
-
-Signed-off-by: Philip Chen <philipchen@chromium.org>
-Reviewed-by: Sam Ravnborg <sam@ravnborg.org>
-Reviewed-by: Douglas Anderson <dianders@chromium.org>
-Reviewed-by: Stephen Boyd <swboyd@chromium.org>
-[dianders: whitespace fixes reported by dim apply-branch]
-Signed-off-by: Douglas Anderson <dianders@chromium.org>
-Link: https://patchwork.freedesktop.org/patch/msgid/20210921110556.v6.2.I1d6ea362dc76efa77cca2b46253d31b7651eaf17@changeid
-Stable-dep-of: fc94224c2e0a ("drm/bridge: parade-ps8640: Fix regulator supply order")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/gpu/drm/bridge/parade-ps8640.c | 180 ++++++++++++++++++++++++-
- 1 file changed, 179 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
-index 88c9f3404ac1..43afa848a36a 100644
---- a/drivers/gpu/drm/bridge/parade-ps8640.c
-+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
-@@ -13,11 +13,36 @@
- #include <linux/regulator/consumer.h>
-
- #include <drm/drm_bridge.h>
-+#include <drm/drm_dp_helper.h>
- #include <drm/drm_mipi_dsi.h>
- #include <drm/drm_of.h>
- #include <drm/drm_panel.h>
- #include <drm/drm_print.h>
-
-+#define PAGE0_AUXCH_CFG3 0x76
-+#define AUXCH_CFG3_RESET 0xff
-+#define PAGE0_SWAUX_ADDR_7_0 0x7d
-+#define PAGE0_SWAUX_ADDR_15_8 0x7e
-+#define PAGE0_SWAUX_ADDR_23_16 0x7f
-+#define SWAUX_ADDR_MASK GENMASK(19, 0)
-+#define PAGE0_SWAUX_LENGTH 0x80
-+#define SWAUX_LENGTH_MASK GENMASK(3, 0)
-+#define SWAUX_NO_PAYLOAD BIT(7)
-+#define PAGE0_SWAUX_WDATA 0x81
-+#define PAGE0_SWAUX_RDATA 0x82
-+#define PAGE0_SWAUX_CTRL 0x83
-+#define SWAUX_SEND BIT(0)
-+#define PAGE0_SWAUX_STATUS 0x84
-+#define SWAUX_M_MASK GENMASK(4, 0)
-+#define SWAUX_STATUS_MASK GENMASK(7, 5)
-+#define SWAUX_STATUS_NACK (0x1 << 5)
-+#define SWAUX_STATUS_DEFER (0x2 << 5)
-+#define SWAUX_STATUS_ACKM (0x3 << 5)
-+#define SWAUX_STATUS_INVALID (0x4 << 5)
-+#define SWAUX_STATUS_I2C_NACK (0x5 << 5)
-+#define SWAUX_STATUS_I2C_DEFER (0x6 << 5)
-+#define SWAUX_STATUS_TIMEOUT (0x7 << 5)
-+
- #define PAGE2_GPIO_H 0xa7
- #define PS_GPIO9 BIT(1)
- #define PAGE2_I2C_BYPASS 0xea
-@@ -66,6 +91,7 @@ enum ps8640_vdo_control {
- struct ps8640 {
- struct drm_bridge bridge;
- struct drm_bridge *panel_bridge;
-+ struct drm_dp_aux aux;
- struct mipi_dsi_device *dsi;
- struct i2c_client *page[MAX_DEVS];
- struct regmap *regmap[MAX_DEVS];
-@@ -115,6 +141,137 @@ static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e)
- return container_of(e, struct ps8640, bridge);
- }
-
-+static inline struct ps8640 *aux_to_ps8640(struct drm_dp_aux *aux)
-+{
-+ return container_of(aux, struct ps8640, aux);
-+}
-+
-+static ssize_t ps8640_aux_transfer(struct drm_dp_aux *aux,
-+ struct drm_dp_aux_msg *msg)
-+{
-+ struct ps8640 *ps_bridge = aux_to_ps8640(aux);
-+ struct regmap *map = ps_bridge->regmap[PAGE0_DP_CNTL];
-+ struct device *dev = &ps_bridge->page[PAGE0_DP_CNTL]->dev;
-+ unsigned int len = msg->size;
-+ unsigned int data;
-+ unsigned int base;
-+ int ret;
-+ u8 request = msg->request &
-+ ~(DP_AUX_I2C_MOT | DP_AUX_I2C_WRITE_STATUS_UPDATE);
-+ u8 *buf = msg->buffer;
-+ u8 addr_len[PAGE0_SWAUX_LENGTH + 1 - PAGE0_SWAUX_ADDR_7_0];
-+ u8 i;
-+ bool is_native_aux = false;
-+
-+ if (len > DP_AUX_MAX_PAYLOAD_BYTES)
-+ return -EINVAL;
-+
-+ if (msg->address & ~SWAUX_ADDR_MASK)
-+ return -EINVAL;
-+
-+ switch (request) {
-+ case DP_AUX_NATIVE_WRITE:
-+ case DP_AUX_NATIVE_READ:
-+ is_native_aux = true;
-+ fallthrough;
-+ case DP_AUX_I2C_WRITE:
-+ case DP_AUX_I2C_READ:
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ ret = regmap_write(map, PAGE0_AUXCH_CFG3, AUXCH_CFG3_RESET);
-+ if (ret) {
-+ DRM_DEV_ERROR(dev, "failed to write PAGE0_AUXCH_CFG3: %d\n",
-+ ret);
-+ return ret;
-+ }
-+
-+ /* Assume it's good */
-+ msg->reply = 0;
-+
-+ base = PAGE0_SWAUX_ADDR_7_0;
-+ addr_len[PAGE0_SWAUX_ADDR_7_0 - base] = msg->address;
-+ addr_len[PAGE0_SWAUX_ADDR_15_8 - base] = msg->address >> 8;
-+ addr_len[PAGE0_SWAUX_ADDR_23_16 - base] = (msg->address >> 16) |
-+ (msg->request << 4);
-+ addr_len[PAGE0_SWAUX_LENGTH - base] = (len == 0) ? SWAUX_NO_PAYLOAD :
-+ ((len - 1) & SWAUX_LENGTH_MASK);
-+
-+ regmap_bulk_write(map, PAGE0_SWAUX_ADDR_7_0, addr_len,
-+ ARRAY_SIZE(addr_len));
-+
-+ if (len && (request == DP_AUX_NATIVE_WRITE ||
-+ request == DP_AUX_I2C_WRITE)) {
-+ /* Write to the internal FIFO buffer */
-+ for (i = 0; i < len; i++) {
-+ ret = regmap_write(map, PAGE0_SWAUX_WDATA, buf[i]);
-+ if (ret) {
-+ DRM_DEV_ERROR(dev,
-+ "failed to write WDATA: %d\n",
-+ ret);
-+ return ret;
-+ }
-+ }
-+ }
-+
-+ regmap_write(map, PAGE0_SWAUX_CTRL, SWAUX_SEND);
-+
-+ /* Zero delay loop because i2c transactions are slow already */
-+ regmap_read_poll_timeout(map, PAGE0_SWAUX_CTRL, data,
-+ !(data & SWAUX_SEND), 0, 50 * 1000);
-+
-+ regmap_read(map, PAGE0_SWAUX_STATUS, &data);
-+ if (ret) {
-+ DRM_DEV_ERROR(dev, "failed to read PAGE0_SWAUX_STATUS: %d\n",
-+ ret);
-+ return ret;
-+ }
-+
-+ switch (data & SWAUX_STATUS_MASK) {
-+ /* Ignore the DEFER cases as they are already handled in hardware */
-+ case SWAUX_STATUS_NACK:
-+ case SWAUX_STATUS_I2C_NACK:
-+ /*
-+ * The programming guide is not clear about whether a I2C NACK
-+ * would trigger SWAUX_STATUS_NACK or SWAUX_STATUS_I2C_NACK. So
-+ * we handle both cases together.
-+ */
-+ if (is_native_aux)
-+ msg->reply |= DP_AUX_NATIVE_REPLY_NACK;
-+ else
-+ msg->reply |= DP_AUX_I2C_REPLY_NACK;
-+
-+ fallthrough;
-+ case SWAUX_STATUS_ACKM:
-+ len = data & SWAUX_M_MASK;
-+ break;
-+ case SWAUX_STATUS_INVALID:
-+ return -EOPNOTSUPP;
-+ case SWAUX_STATUS_TIMEOUT:
-+ return -ETIMEDOUT;
-+ }
-+
-+ if (len && (request == DP_AUX_NATIVE_READ ||
-+ request == DP_AUX_I2C_READ)) {
-+ /* Read from the internal FIFO buffer */
-+ for (i = 0; i < len; i++) {
-+ ret = regmap_read(map, PAGE0_SWAUX_RDATA, &data);
-+ if (ret) {
-+ DRM_DEV_ERROR(dev,
-+ "failed to read RDATA: %d\n",
-+ ret);
-+ return ret;
-+ }
-+
-+ buf[i] = data;
-+ }
-+ }
-+
-+ return len;
-+}
-+
- static int ps8640_bridge_vdo_control(struct ps8640 *ps_bridge,
- const enum ps8640_vdo_control ctrl)
- {
-@@ -284,18 +441,33 @@ static int ps8640_bridge_attach(struct drm_bridge *bridge,
- dsi->format = MIPI_DSI_FMT_RGB888;
- dsi->lanes = DP_NUM_LANES;
- ret = mipi_dsi_attach(dsi);
-- if (ret)
-+ if (ret) {
-+ dev_err(dev, "failed to attach dsi device: %d\n", ret);
- goto err_dsi_attach;
-+ }
-+
-+ ret = drm_dp_aux_register(&ps_bridge->aux);
-+ if (ret) {
-+ dev_err(dev, "failed to register DP AUX channel: %d\n", ret);
-+ goto err_aux_register;
-+ }
-
- /* Attach the panel-bridge to the dsi bridge */
- return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge,
- &ps_bridge->bridge, flags);
-
-+err_aux_register:
-+ mipi_dsi_detach(dsi);
- err_dsi_attach:
- mipi_dsi_device_unregister(dsi);
- return ret;
- }
-
-+static void ps8640_bridge_detach(struct drm_bridge *bridge)
-+{
-+ drm_dp_aux_unregister(&bridge_to_ps8640(bridge)->aux);
-+}
-+
- static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge,
- struct drm_connector *connector)
- {
-@@ -332,6 +504,7 @@ static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge,
-
- static const struct drm_bridge_funcs ps8640_bridge_funcs = {
- .attach = ps8640_bridge_attach,
-+ .detach = ps8640_bridge_detach,
- .get_edid = ps8640_bridge_get_edid,
- .post_disable = ps8640_post_disable,
- .pre_enable = ps8640_pre_enable,
-@@ -407,6 +580,11 @@ static int ps8640_probe(struct i2c_client *client)
-
- i2c_set_clientdata(client, ps_bridge);
-
-+ ps_bridge->aux.name = "parade-ps8640-aux";
-+ ps_bridge->aux.dev = dev;
-+ ps_bridge->aux.transfer = ps8640_aux_transfer;
-+ drm_dp_aux_init(&ps_bridge->aux);
-+
- drm_bridge_add(&ps_bridge->bridge);
-
- return 0;
---
-2.35.1
-
+++ /dev/null
-From f911e7903705123552b722cc5f997dc674f91bfe Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 28 Oct 2021 10:58:10 -0700
-Subject: drm/bridge: parade-ps8640: Enable runtime power management
-
-From: Philip Chen <philipchen@chromium.org>
-
-[ Upstream commit 826cff3f7ebba460d3db61f135798ce76b0d26ed ]
-
-Fit ps8640 driver into runtime power management framework:
-
-First, break _poweron() to 3 parts: (1) turn on power and wait for
-ps8640's internal MCU to finish init (2) check panel HPD (which is
-proxied by GPIO9) (3) the other configs. As runtime_resume() can be
-called before panel is powered, we only add (1) to _resume() and leave
-(2)(3) to _pre_enable(). We also add (2) to _aux_transfer() as we want
-to ensure panel HPD is asserted before we start AUX CH transactions.
-
-Second, the original driver has a mysterious delay of 50 ms between (2)
-and (3). Since Parade's support can't explain what the delay is for,
-and we don't see removing the delay break any boards at hand, remove
-the delay to fit into this driver change.
-
-In addition, rename "powered" to "pre_enabled" and don't check for it
-in the pm_runtime calls. The pm_runtime calls are already refcounted
-so there's no reason to check there. The other user of "powered",
-_get_edid(), only cares if pre_enable() has already been called.
-
-Lastly, change some existing DRM_...() logging to dev_...() along the
-way, since DRM_...() seem to be deprecated in [1].
-
-[1] https://patchwork.freedesktop.org/patch/454760/
-
-Signed-off-by: Philip Chen <philipchen@chromium.org>
-Reviewed-by: Douglas Anderson <dianders@chromium.org>
-Reviewed-by: Stephen Boyd <swboyd@chromium.org>
-[dianders: fixed whitespace warning reported by dim tool]
-Signed-off-by: Douglas Anderson <dianders@chromium.org>
-Link: https://patchwork.freedesktop.org/patch/msgid/20211028105754.v5.1.I828f5db745535fb7e36e8ffdd62d546f6d08b6d1@changeid
-Stable-dep-of: fc94224c2e0a ("drm/bridge: parade-ps8640: Fix regulator supply order")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/gpu/drm/bridge/parade-ps8640.c | 190 ++++++++++++++++---------
- 1 file changed, 119 insertions(+), 71 deletions(-)
-
-diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
-index 43afa848a36a..52f2ea6fcb26 100644
---- a/drivers/gpu/drm/bridge/parade-ps8640.c
-+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
-@@ -9,6 +9,7 @@
- #include <linux/i2c.h>
- #include <linux/module.h>
- #include <linux/of_graph.h>
-+#include <linux/pm_runtime.h>
- #include <linux/regmap.h>
- #include <linux/regulator/consumer.h>
-
-@@ -98,7 +99,7 @@ struct ps8640 {
- struct regulator_bulk_data supplies[2];
- struct gpio_desc *gpio_reset;
- struct gpio_desc *gpio_powerdown;
-- bool powered;
-+ bool pre_enabled;
- };
-
- static const struct regmap_config ps8640_regmap_config[] = {
-@@ -146,8 +147,29 @@ static inline struct ps8640 *aux_to_ps8640(struct drm_dp_aux *aux)
- return container_of(aux, struct ps8640, aux);
- }
-
--static ssize_t ps8640_aux_transfer(struct drm_dp_aux *aux,
-- struct drm_dp_aux_msg *msg)
-+static int ps8640_ensure_hpd(struct ps8640 *ps_bridge)
-+{
-+ struct regmap *map = ps_bridge->regmap[PAGE2_TOP_CNTL];
-+ struct device *dev = &ps_bridge->page[PAGE2_TOP_CNTL]->dev;
-+ int status;
-+ int ret;
-+
-+ /*
-+ * Apparently something about the firmware in the chip signals that
-+ * HPD goes high by reporting GPIO9 as high (even though HPD isn't
-+ * actually connected to GPIO9).
-+ */
-+ ret = regmap_read_poll_timeout(map, PAGE2_GPIO_H, status,
-+ status & PS_GPIO9, 20 * 1000, 200 * 1000);
-+
-+ if (ret < 0)
-+ dev_warn(dev, "HPD didn't go high: %d\n", ret);
-+
-+ return ret;
-+}
-+
-+static ssize_t ps8640_aux_transfer_msg(struct drm_dp_aux *aux,
-+ struct drm_dp_aux_msg *msg)
- {
- struct ps8640 *ps_bridge = aux_to_ps8640(aux);
- struct regmap *map = ps_bridge->regmap[PAGE0_DP_CNTL];
-@@ -272,38 +294,49 @@ static ssize_t ps8640_aux_transfer(struct drm_dp_aux *aux,
- return len;
- }
-
--static int ps8640_bridge_vdo_control(struct ps8640 *ps_bridge,
-- const enum ps8640_vdo_control ctrl)
-+static ssize_t ps8640_aux_transfer(struct drm_dp_aux *aux,
-+ struct drm_dp_aux_msg *msg)
-+{
-+ struct ps8640 *ps_bridge = aux_to_ps8640(aux);
-+ struct device *dev = &ps_bridge->page[PAGE0_DP_CNTL]->dev;
-+ int ret;
-+
-+ pm_runtime_get_sync(dev);
-+ ret = ps8640_ensure_hpd(ps_bridge);
-+ if (!ret)
-+ ret = ps8640_aux_transfer_msg(aux, msg);
-+ pm_runtime_mark_last_busy(dev);
-+ pm_runtime_put_autosuspend(dev);
-+
-+ return ret;
-+}
-+
-+static void ps8640_bridge_vdo_control(struct ps8640 *ps_bridge,
-+ const enum ps8640_vdo_control ctrl)
- {
- struct regmap *map = ps_bridge->regmap[PAGE3_DSI_CNTL1];
-+ struct device *dev = &ps_bridge->page[PAGE3_DSI_CNTL1]->dev;
- u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, ctrl };
- int ret;
-
- ret = regmap_bulk_write(map, PAGE3_SET_ADD,
- vdo_ctrl_buf, sizeof(vdo_ctrl_buf));
-
-- if (ret < 0) {
-- DRM_ERROR("failed to %sable VDO: %d\n",
-- ctrl == ENABLE ? "en" : "dis", ret);
-- return ret;
-- }
--
-- return 0;
-+ if (ret < 0)
-+ dev_err(dev, "failed to %sable VDO: %d\n",
-+ ctrl == ENABLE ? "en" : "dis", ret);
- }
-
--static void ps8640_bridge_poweron(struct ps8640 *ps_bridge)
-+static int __maybe_unused ps8640_resume(struct device *dev)
- {
-- struct regmap *map = ps_bridge->regmap[PAGE2_TOP_CNTL];
-- int ret, status;
--
-- if (ps_bridge->powered)
-- return;
-+ struct ps8640 *ps_bridge = dev_get_drvdata(dev);
-+ int ret;
-
- ret = regulator_bulk_enable(ARRAY_SIZE(ps_bridge->supplies),
- ps_bridge->supplies);
- if (ret < 0) {
-- DRM_ERROR("cannot enable regulators %d\n", ret);
-- return;
-+ dev_err(dev, "cannot enable regulators %d\n", ret);
-+ return ret;
- }
-
- gpiod_set_value(ps_bridge->gpio_powerdown, 0);
-@@ -312,86 +345,78 @@ static void ps8640_bridge_poweron(struct ps8640 *ps_bridge)
- gpiod_set_value(ps_bridge->gpio_reset, 0);
-
- /*
-- * Wait for the ps8640 embedded MCU to be ready
-- * First wait 200ms and then check the MCU ready flag every 20ms
-+ * Mystery 200 ms delay for the "MCU to be ready". It's unclear if
-+ * this is truly necessary since the MCU will already signal that
-+ * things are "good to go" by signaling HPD on "gpio 9". See
-+ * ps8640_ensure_hpd(). For now we'll keep this mystery delay just in
-+ * case.
- */
- msleep(200);
-
-- ret = regmap_read_poll_timeout(map, PAGE2_GPIO_H, status,
-- status & PS_GPIO9, 20 * 1000, 200 * 1000);
--
-- if (ret < 0) {
-- DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", ret);
-- goto err_regulators_disable;
-- }
--
-- msleep(50);
--
-- /*
-- * The Manufacturer Command Set (MCS) is a device dependent interface
-- * intended for factory programming of the display module default
-- * parameters. Once the display module is configured, the MCS shall be
-- * disabled by the manufacturer. Once disabled, all MCS commands are
-- * ignored by the display interface.
-- */
--
-- ret = regmap_update_bits(map, PAGE2_MCS_EN, MCS_EN, 0);
-- if (ret < 0) {
-- DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
-- goto err_regulators_disable;
-- }
--
-- /* Switch access edp panel's edid through i2c */
-- ret = regmap_write(map, PAGE2_I2C_BYPASS, I2C_BYPASS_EN);
-- if (ret < 0) {
-- DRM_ERROR("failed write PAGE2_I2C_BYPASS: %d\n", ret);
-- goto err_regulators_disable;
-- }
--
-- ps_bridge->powered = true;
--
-- return;
--
--err_regulators_disable:
-- regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
-- ps_bridge->supplies);
-+ return 0;
- }
-
--static void ps8640_bridge_poweroff(struct ps8640 *ps_bridge)
-+static int __maybe_unused ps8640_suspend(struct device *dev)
- {
-+ struct ps8640 *ps_bridge = dev_get_drvdata(dev);
- int ret;
-
-- if (!ps_bridge->powered)
-- return;
--
- gpiod_set_value(ps_bridge->gpio_reset, 1);
- gpiod_set_value(ps_bridge->gpio_powerdown, 1);
- ret = regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
- ps_bridge->supplies);
- if (ret < 0)
-- DRM_ERROR("cannot disable regulators %d\n", ret);
-+ dev_err(dev, "cannot disable regulators %d\n", ret);
-
-- ps_bridge->powered = false;
-+ return ret;
- }
-
-+static const struct dev_pm_ops ps8640_pm_ops = {
-+ SET_RUNTIME_PM_OPS(ps8640_suspend, ps8640_resume, NULL)
-+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-+ pm_runtime_force_resume)
-+};
-+
- static void ps8640_pre_enable(struct drm_bridge *bridge)
- {
- struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
-+ struct regmap *map = ps_bridge->regmap[PAGE2_TOP_CNTL];
-+ struct device *dev = &ps_bridge->page[PAGE0_DP_CNTL]->dev;
- int ret;
-
-- ps8640_bridge_poweron(ps_bridge);
-+ pm_runtime_get_sync(dev);
-+ ps8640_ensure_hpd(ps_bridge);
-
-- ret = ps8640_bridge_vdo_control(ps_bridge, ENABLE);
-+ /*
-+ * The Manufacturer Command Set (MCS) is a device dependent interface
-+ * intended for factory programming of the display module default
-+ * parameters. Once the display module is configured, the MCS shall be
-+ * disabled by the manufacturer. Once disabled, all MCS commands are
-+ * ignored by the display interface.
-+ */
-+
-+ ret = regmap_update_bits(map, PAGE2_MCS_EN, MCS_EN, 0);
-+ if (ret < 0)
-+ dev_warn(dev, "failed write PAGE2_MCS_EN: %d\n", ret);
-+
-+ /* Switch access edp panel's edid through i2c */
-+ ret = regmap_write(map, PAGE2_I2C_BYPASS, I2C_BYPASS_EN);
- if (ret < 0)
-- ps8640_bridge_poweroff(ps_bridge);
-+ dev_warn(dev, "failed write PAGE2_MCS_EN: %d\n", ret);
-+
-+ ps8640_bridge_vdo_control(ps_bridge, ENABLE);
-+
-+ ps_bridge->pre_enabled = true;
- }
-
- static void ps8640_post_disable(struct drm_bridge *bridge)
- {
- struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
-
-+ ps_bridge->pre_enabled = false;
-+
- ps8640_bridge_vdo_control(ps_bridge, DISABLE);
-- ps8640_bridge_poweroff(ps_bridge);
-+ pm_runtime_put_sync_suspend(&ps_bridge->page[PAGE0_DP_CNTL]->dev);
- }
-
- static int ps8640_bridge_attach(struct drm_bridge *bridge,
-@@ -472,7 +497,7 @@ static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge,
- struct drm_connector *connector)
- {
- struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
-- bool poweroff = !ps_bridge->powered;
-+ bool poweroff = !ps_bridge->pre_enabled;
- struct edid *edid;
-
- /*
-@@ -502,6 +527,12 @@ static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge,
- return edid;
- }
-
-+static void ps8640_runtime_disable(void *data)
-+{
-+ pm_runtime_dont_use_autosuspend(data);
-+ pm_runtime_disable(data);
-+}
-+
- static const struct drm_bridge_funcs ps8640_bridge_funcs = {
- .attach = ps8640_bridge_attach,
- .detach = ps8640_bridge_detach,
-@@ -585,6 +616,22 @@ static int ps8640_probe(struct i2c_client *client)
- ps_bridge->aux.transfer = ps8640_aux_transfer;
- drm_dp_aux_init(&ps_bridge->aux);
-
-+ pm_runtime_enable(dev);
-+ /*
-+ * Powering on ps8640 takes ~300ms. To avoid wasting time on power
-+ * cycling ps8640 too often, set autosuspend_delay to 500ms to ensure
-+ * the bridge wouldn't suspend in between each _aux_transfer_msg() call
-+ * during EDID read (~20ms in my experiment) and in between the last
-+ * _aux_transfer_msg() call during EDID read and the _pre_enable() call
-+ * (~100ms in my experiment).
-+ */
-+ pm_runtime_set_autosuspend_delay(dev, 500);
-+ pm_runtime_use_autosuspend(dev);
-+ pm_suspend_ignore_children(dev, true);
-+ ret = devm_add_action_or_reset(dev, ps8640_runtime_disable, dev);
-+ if (ret)
-+ return ret;
-+
- drm_bridge_add(&ps_bridge->bridge);
-
- return 0;
-@@ -611,6 +658,7 @@ static struct i2c_driver ps8640_driver = {
- .driver = {
- .name = "ps8640",
- .of_match_table = ps8640_match,
-+ .pm = &ps8640_pm_ops,
- },
- };
- module_i2c_driver(ps8640_driver);
---
-2.35.1
-
Signed-off-by: Robert Foss <robert.foss@linaro.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20220721092258.3397461-1-wenst@chromium.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
- drivers/gpu/drm/bridge/parade-ps8640.c | 4 ++--
+ drivers/gpu/drm/bridge/parade-ps8640.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
-diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
-index 3de796cf9328..f0ab75a5ea41 100644
--- a/drivers/gpu/drm/bridge/parade-ps8640.c
+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
-@@ -572,8 +572,8 @@ static int ps8640_probe(struct i2c_client *client)
- if (!ps_bridge)
- return -ENOMEM;
+@@ -333,8 +333,8 @@ static int ps8640_probe(struct i2c_clien
+ if (IS_ERR(ps_bridge->panel_bridge))
+ return PTR_ERR(ps_bridge->panel_bridge);
- ps_bridge->supplies[0].supply = "vdd33";
- ps_bridge->supplies[1].supply = "vdd12";
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies),
ps_bridge->supplies);
if (ret)
---
-2.35.1
-
+++ /dev/null
-From 7c5fbace745bb2f2268545c25c495e0bea111cbb Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 28 Oct 2021 10:58:11 -0700
-Subject: drm/bridge: parade-ps8640: Populate devices on aux-bus
-
-From: Philip Chen <philipchen@chromium.org>
-
-[ Upstream commit e9d9f9582c3d90bced286a63d1f718d4aae60a03 ]
-
-Conventionally, panel is listed under the root of the device tree.
-When userland asks for display mode, ps8640 bridge is responsible
-for returning EDID when ps8640_bridge_get_edid() is called.
-
-Now enable a new option of listing panel under "aux-bus" of ps8640
-bridge node in the device tree. In this case, panel driver can retrieve
-EDID by triggering AUX transactions, without ps8640_bridge_get_edid()
-calls at all.
-
-To prevent the "old" and "new" options from interfering with each
-other's logic flow, disable DRM_BRIDGE_OP_EDID when the new option
-is taken.
-
-Signed-off-by: Philip Chen <philipchen@chromium.org>
-Reviewed-by: Stephen Boyd <swboyd@chromium.org>
-Reviewed-by: Douglas Anderson <dianders@chromium.org>
-Signed-off-by: Douglas Anderson <dianders@chromium.org>
-Link: https://patchwork.freedesktop.org/patch/msgid/20211028105754.v5.2.I09899dea340f11feab97d719cb4b62bef3179e4b@changeid
-Stable-dep-of: fc94224c2e0a ("drm/bridge: parade-ps8640: Fix regulator supply order")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/gpu/drm/bridge/Kconfig | 1 +
- drivers/gpu/drm/bridge/parade-ps8640.c | 51 ++++++++++++++++++++------
- 2 files changed, 40 insertions(+), 12 deletions(-)
-
-diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
-index 68ec45abc1fb..44ad70939663 100644
---- a/drivers/gpu/drm/bridge/Kconfig
-+++ b/drivers/gpu/drm/bridge/Kconfig
-@@ -182,6 +182,7 @@ config DRM_PARADE_PS8622
- config DRM_PARADE_PS8640
- tristate "Parade PS8640 MIPI DSI to eDP Converter"
- depends on OF
-+ select DRM_DP_AUX_BUS
- select DRM_KMS_HELPER
- select DRM_MIPI_DSI
- select DRM_PANEL
-diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
-index 52f2ea6fcb26..3de796cf9328 100644
---- a/drivers/gpu/drm/bridge/parade-ps8640.c
-+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
-@@ -14,6 +14,7 @@
- #include <linux/regulator/consumer.h>
-
- #include <drm/drm_bridge.h>
-+#include <drm/drm_dp_aux_bus.h>
- #include <drm/drm_dp_helper.h>
- #include <drm/drm_mipi_dsi.h>
- #include <drm/drm_of.h>
-@@ -147,6 +148,23 @@ static inline struct ps8640 *aux_to_ps8640(struct drm_dp_aux *aux)
- return container_of(aux, struct ps8640, aux);
- }
-
-+static bool ps8640_of_panel_on_aux_bus(struct device *dev)
-+{
-+ struct device_node *bus, *panel;
-+
-+ bus = of_get_child_by_name(dev->of_node, "aux-bus");
-+ if (!bus)
-+ return false;
-+
-+ panel = of_get_child_by_name(bus, "panel");
-+ of_node_put(bus);
-+ if (!panel)
-+ return false;
-+ of_node_put(panel);
-+
-+ return true;
-+}
-+
- static int ps8640_ensure_hpd(struct ps8640 *ps_bridge)
- {
- struct regmap *map = ps_bridge->regmap[PAGE2_TOP_CNTL];
-@@ -554,17 +572,6 @@ static int ps8640_probe(struct i2c_client *client)
- if (!ps_bridge)
- return -ENOMEM;
-
-- /* port@1 is ps8640 output port */
-- ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL);
-- if (ret < 0)
-- return ret;
-- if (!panel)
-- return -ENODEV;
--
-- ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
-- if (IS_ERR(ps_bridge->panel_bridge))
-- return PTR_ERR(ps_bridge->panel_bridge);
--
- ps_bridge->supplies[0].supply = "vdd33";
- ps_bridge->supplies[1].supply = "vdd12";
- ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies),
-@@ -587,9 +594,16 @@ static int ps8640_probe(struct i2c_client *client)
-
- ps_bridge->bridge.funcs = &ps8640_bridge_funcs;
- ps_bridge->bridge.of_node = dev->of_node;
-- ps_bridge->bridge.ops = DRM_BRIDGE_OP_EDID;
- ps_bridge->bridge.type = DRM_MODE_CONNECTOR_eDP;
-
-+ /*
-+ * In the device tree, if panel is listed under aux-bus of the bridge
-+ * node, panel driver should be able to retrieve EDID by itself using
-+ * aux-bus. So let's not set DRM_BRIDGE_OP_EDID here.
-+ */
-+ if (!ps8640_of_panel_on_aux_bus(&client->dev))
-+ ps_bridge->bridge.ops = DRM_BRIDGE_OP_EDID;
-+
- ps_bridge->page[PAGE0_DP_CNTL] = client;
-
- ps_bridge->regmap[PAGE0_DP_CNTL] = devm_regmap_init_i2c(client, ps8640_regmap_config);
-@@ -632,6 +646,19 @@ static int ps8640_probe(struct i2c_client *client)
- if (ret)
- return ret;
-
-+ devm_of_dp_aux_populate_ep_devices(&ps_bridge->aux);
-+
-+ /* port@1 is ps8640 output port */
-+ ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL);
-+ if (ret < 0)
-+ return ret;
-+ if (!panel)
-+ return -ENODEV;
-+
-+ ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
-+ if (IS_ERR(ps_bridge->panel_bridge))
-+ return PTR_ERR(ps_bridge->panel_bridge);
-+
- drm_bridge_add(&ps_bridge->bridge);
-
- return 0;
---
-2.35.1
-
+++ /dev/null
-From 85a877c02788c394efcf8308482dabfa98117eb0 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 21 Sep 2021 11:06:16 -0700
-Subject: drm/bridge: parade-ps8640: Use regmap APIs
-
-From: Philip Chen <philipchen@chromium.org>
-
-[ Upstream commit 692d8db0a5ca123017d7d4847856343512f87af9 ]
-
-Replace the direct i2c access (i2c_smbus_* functions) with regmap APIs,
-which will simplify the future update on ps8640 driver.
-
-Signed-off-by: Philip Chen <philipchen@chromium.org>
-Reviewed-by: Douglas Anderson <dianders@chromium.org>
-Acked-by: Sam Ravnborg <sam@ravnborg.org>
-Reviewed-by: Stephen Boyd <swboyd@chromium.org>
-[dianders: whitespace fixes reported by dim apply-branch]
-Signed-off-by: Douglas Anderson <dianders@chromium.org>
-Link: https://patchwork.freedesktop.org/patch/msgid/20210921110556.v6.1.I2351df94f18d5d8debc22d4d100f36fac560409a@changeid
-Stable-dep-of: fc94224c2e0a ("drm/bridge: parade-ps8640: Fix regulator supply order")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/gpu/drm/bridge/parade-ps8640.c | 94 ++++++++++++++++++--------
- 1 file changed, 64 insertions(+), 30 deletions(-)
-
-diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
-index 7bd0affa057a..88c9f3404ac1 100644
---- a/drivers/gpu/drm/bridge/parade-ps8640.c
-+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
-@@ -9,6 +9,7 @@
- #include <linux/i2c.h>
- #include <linux/module.h>
- #include <linux/of_graph.h>
-+#include <linux/regmap.h>
- #include <linux/regulator/consumer.h>
-
- #include <drm/drm_bridge.h>
-@@ -29,6 +30,11 @@
- #define VDO_EN 0x1c
- #define DP_NUM_LANES 4
-
-+#define COMMON_PS8640_REGMAP_CONFIG \
-+ .reg_bits = 8, \
-+ .val_bits = 8, \
-+ .cache_type = REGCACHE_NONE
-+
- /*
- * PS8640 uses multiple addresses:
- * page[0]: for DP control
-@@ -62,12 +68,48 @@ struct ps8640 {
- struct drm_bridge *panel_bridge;
- struct mipi_dsi_device *dsi;
- struct i2c_client *page[MAX_DEVS];
-+ struct regmap *regmap[MAX_DEVS];
- struct regulator_bulk_data supplies[2];
- struct gpio_desc *gpio_reset;
- struct gpio_desc *gpio_powerdown;
- bool powered;
- };
-
-+static const struct regmap_config ps8640_regmap_config[] = {
-+ [PAGE0_DP_CNTL] = {
-+ COMMON_PS8640_REGMAP_CONFIG,
-+ .max_register = 0xbf,
-+ },
-+ [PAGE1_VDO_BDG] = {
-+ COMMON_PS8640_REGMAP_CONFIG,
-+ .max_register = 0xff,
-+ },
-+ [PAGE2_TOP_CNTL] = {
-+ COMMON_PS8640_REGMAP_CONFIG,
-+ .max_register = 0xff,
-+ },
-+ [PAGE3_DSI_CNTL1] = {
-+ COMMON_PS8640_REGMAP_CONFIG,
-+ .max_register = 0xff,
-+ },
-+ [PAGE4_MIPI_PHY] = {
-+ COMMON_PS8640_REGMAP_CONFIG,
-+ .max_register = 0xff,
-+ },
-+ [PAGE5_VPLL] = {
-+ COMMON_PS8640_REGMAP_CONFIG,
-+ .max_register = 0x7f,
-+ },
-+ [PAGE6_DSI_CNTL2] = {
-+ COMMON_PS8640_REGMAP_CONFIG,
-+ .max_register = 0xff,
-+ },
-+ [PAGE7_SPI_CNTL] = {
-+ COMMON_PS8640_REGMAP_CONFIG,
-+ .max_register = 0xff,
-+ },
-+};
-+
- static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e)
- {
- return container_of(e, struct ps8640, bridge);
-@@ -76,13 +118,13 @@ static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e)
- static int ps8640_bridge_vdo_control(struct ps8640 *ps_bridge,
- const enum ps8640_vdo_control ctrl)
- {
-- struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1];
-+ struct regmap *map = ps_bridge->regmap[PAGE3_DSI_CNTL1];
- u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, ctrl };
- int ret;
-
-- ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD,
-- sizeof(vdo_ctrl_buf),
-- vdo_ctrl_buf);
-+ ret = regmap_bulk_write(map, PAGE3_SET_ADD,
-+ vdo_ctrl_buf, sizeof(vdo_ctrl_buf));
-+
- if (ret < 0) {
- DRM_ERROR("failed to %sable VDO: %d\n",
- ctrl == ENABLE ? "en" : "dis", ret);
-@@ -94,8 +136,7 @@ static int ps8640_bridge_vdo_control(struct ps8640 *ps_bridge,
-
- static void ps8640_bridge_poweron(struct ps8640 *ps_bridge)
- {
-- struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL];
-- unsigned long timeout;
-+ struct regmap *map = ps_bridge->regmap[PAGE2_TOP_CNTL];
- int ret, status;
-
- if (ps_bridge->powered)
-@@ -119,18 +160,12 @@ static void ps8640_bridge_poweron(struct ps8640 *ps_bridge)
- */
- msleep(200);
-
-- timeout = jiffies + msecs_to_jiffies(200) + 1;
--
-- while (time_is_after_jiffies(timeout)) {
-- status = i2c_smbus_read_byte_data(client, PAGE2_GPIO_H);
-- if (status < 0) {
-- DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", status);
-- goto err_regulators_disable;
-- }
-- if ((status & PS_GPIO9) == PS_GPIO9)
-- break;
-+ ret = regmap_read_poll_timeout(map, PAGE2_GPIO_H, status,
-+ status & PS_GPIO9, 20 * 1000, 200 * 1000);
-
-- msleep(20);
-+ if (ret < 0) {
-+ DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", ret);
-+ goto err_regulators_disable;
- }
-
- msleep(50);
-@@ -142,22 +177,15 @@ static void ps8640_bridge_poweron(struct ps8640 *ps_bridge)
- * disabled by the manufacturer. Once disabled, all MCS commands are
- * ignored by the display interface.
- */
-- status = i2c_smbus_read_byte_data(client, PAGE2_MCS_EN);
-- if (status < 0) {
-- DRM_ERROR("failed read PAGE2_MCS_EN: %d\n", status);
-- goto err_regulators_disable;
-- }
-
-- ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN,
-- status & ~MCS_EN);
-+ ret = regmap_update_bits(map, PAGE2_MCS_EN, MCS_EN, 0);
- if (ret < 0) {
- DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret);
- goto err_regulators_disable;
- }
-
- /* Switch access edp panel's edid through i2c */
-- ret = i2c_smbus_write_byte_data(client, PAGE2_I2C_BYPASS,
-- I2C_BYPASS_EN);
-+ ret = regmap_write(map, PAGE2_I2C_BYPASS, I2C_BYPASS_EN);
- if (ret < 0) {
- DRM_ERROR("failed write PAGE2_I2C_BYPASS: %d\n", ret);
- goto err_regulators_disable;
-@@ -360,15 +388,21 @@ static int ps8640_probe(struct i2c_client *client)
-
- ps_bridge->page[PAGE0_DP_CNTL] = client;
-
-+ ps_bridge->regmap[PAGE0_DP_CNTL] = devm_regmap_init_i2c(client, ps8640_regmap_config);
-+ if (IS_ERR(ps_bridge->regmap[PAGE0_DP_CNTL]))
-+ return PTR_ERR(ps_bridge->regmap[PAGE0_DP_CNTL]);
-+
- for (i = 1; i < ARRAY_SIZE(ps_bridge->page); i++) {
- ps_bridge->page[i] = devm_i2c_new_dummy_device(&client->dev,
- client->adapter,
- client->addr + i);
-- if (IS_ERR(ps_bridge->page[i])) {
-- dev_err(dev, "failed i2c dummy device, address %02x\n",
-- client->addr + i);
-+ if (IS_ERR(ps_bridge->page[i]))
- return PTR_ERR(ps_bridge->page[i]);
-- }
-+
-+ ps_bridge->regmap[i] = devm_regmap_init_i2c(ps_bridge->page[i],
-+ ps8640_regmap_config + i);
-+ if (IS_ERR(ps_bridge->regmap[i]))
-+ return PTR_ERR(ps_bridge->regmap[i]);
- }
-
- i2c_set_clientdata(client, ps_bridge);
---
-2.35.1
-
drm-bridge-avoid-uninitialized-variable-warning.patch
drm-mipi-dsi-detach-devices-when-removing-the-host.patch
drm-virtio-correct-drm_gem_shmem_get_sg_table-error-.patch
-drm-bridge-parade-ps8640-use-regmap-apis.patch
-drm-bridge-parade-ps8640-add-support-for-aux-channel.patch
-drm-bridge-parade-ps8640-enable-runtime-power-manage.patch
-drm-bridge-parade-ps8640-populate-devices-on-aux-bus.patch
drm-bridge-parade-ps8640-fix-regulator-supply-order.patch
net-wwan-t7xx-add-control-dma-interface.patch
drm-dp_mst-fix-drm_dp_dpcd_read-return-value-checks.patch