From: Xin Ji xji@analogixsemi.com
Send DPCD command to downstream before anx7625 power down, let downstream monitor enter into standby mode.
Signed-off-by: Xin Ji xji@analogixsemi.com Signed-off-by: Hsin-Yi Wang hsinyi@chromium.org --- v3->v4: Use common DP_AUX_NATIVE_READ/WRITE
Previously in: https://patchwork.kernel.org/project/dri-devel/patch/1f36f8bf0a48fb2bba17bac... --- drivers/gpu/drm/bridge/analogix/anx7625.c | 42 +++++++++++++++++++---- drivers/gpu/drm/bridge/analogix/anx7625.h | 2 -- 2 files changed, 35 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 76662fce4ce61d..17b23940549a42 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -129,6 +129,23 @@ static int anx7625_reg_write(struct anx7625_data *ctx, return ret; }
+static int anx7625_reg_block_write(struct anx7625_data *ctx, + struct i2c_client *client, + u8 reg_addr, u8 len, u8 *buf) +{ + int ret; + struct device *dev = &client->dev; + + i2c_access_workaround(ctx, client); + + ret = i2c_smbus_write_i2c_block_data(client, reg_addr, len, buf); + if (ret < 0) + dev_err(dev, "write i2c block failed id=%x\n:%x", + client->addr, reg_addr); + + return ret; +} + static int anx7625_write_or(struct anx7625_data *ctx, struct i2c_client *client, u8 offset, u8 mask) @@ -214,8 +231,8 @@ static int wait_aux_op_finish(struct anx7625_data *ctx) return 0; }
-static int anx7625_aux_dpcd_read(struct anx7625_data *ctx, - u32 address, u8 len, u8 *buf) +static int anx7625_aux_dpcd_trans(struct anx7625_data *ctx, u8 op, + u32 address, u8 len, u8 *buf) { struct device *dev = &ctx->client->dev; int ret; @@ -231,8 +248,7 @@ static int anx7625_aux_dpcd_read(struct anx7625_data *ctx, addrm = (address >> 8) & 0xFF; addrh = (address >> 16) & 0xFF;
- cmd = DPCD_CMD(len, DPCD_READ); - cmd = ((len - 1) << 4) | 0x09; + cmd = DPCD_CMD(len, op);
/* Set command and length */ ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, @@ -246,6 +262,9 @@ static int anx7625_aux_dpcd_read(struct anx7625_data *ctx, ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, AP_AUX_ADDR_19_16, addrh);
+ if (op == DP_AUX_NATIVE_WRITE) + ret |= anx7625_reg_block_write(ctx, ctx->i2c.rx_p0_client, + AP_AUX_BUFF_START, len, buf); /* Enable aux access */ ret |= anx7625_write_or(ctx, ctx->i2c.rx_p0_client, AP_AUX_CTRL_STATUS, AP_AUX_CTRL_OP_EN); @@ -255,14 +274,17 @@ static int anx7625_aux_dpcd_read(struct anx7625_data *ctx, return -EIO; }
- usleep_range(2000, 2100); - ret = wait_aux_op_finish(ctx); if (ret) { dev_err(dev, "aux IO error: wait aux op finish.\n"); return ret; }
+ /* Write done */ + if (op == DP_AUX_NATIVE_WRITE) + return 0; + + /* Read done, read out dpcd data */ ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client, AP_AUX_BUFF_START, len, buf); if (ret < 0) { @@ -845,7 +867,7 @@ static int anx7625_hdcp_enable(struct anx7625_data *ctx) }
/* Read downstream capability */ - anx7625_aux_dpcd_read(ctx, 0x68028, 1, &bcap); + anx7625_aux_dpcd_trans(ctx, DP_AUX_NATIVE_READ, 0x68028, 1, &bcap); if (!(bcap & 0x01)) { pr_warn("downstream not support HDCP 1.4, cap(%x).\n", bcap); return 0; @@ -918,6 +940,7 @@ static void anx7625_dp_stop(struct anx7625_data *ctx) { struct device *dev = &ctx->client->dev; int ret; + u8 data;
DRM_DEV_DEBUG_DRIVER(dev, "stop dp output\n");
@@ -929,6 +952,11 @@ static void anx7625_dp_stop(struct anx7625_data *ctx) ret |= anx7625_write_and(ctx, ctx->i2c.tx_p2_client, 0x08, 0x7f);
ret |= anx7625_video_mute_control(ctx, 1); + + dev_dbg(dev, "notify downstream enter into standby\n"); + /* Downstream monitor enter into standby mode */ + data = 2; + ret |= anx7625_aux_dpcd_trans(ctx, DP_AUX_NATIVE_WRITE, 0x000600, 1, &data); if (ret < 0) DRM_DEV_ERROR(dev, "IO error : mute video fail\n");
diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h b/drivers/gpu/drm/bridge/analogix/anx7625.h index 56165f5b254c14..64a8ab56529404 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.h +++ b/drivers/gpu/drm/bridge/analogix/anx7625.h @@ -242,8 +242,6 @@
#define AP_AUX_COMMAND 0x27 /* com+len */ #define LENGTH_SHIFT 4 -#define DPCD_READ 0x09 -#define DPCD_WRITE 0x08 #define DPCD_CMD(len, cmd) ((((len) - 1) << LENGTH_SHIFT) | (cmd))
/* Bit 0&1: 3D video structure */
Use devm_kzalloc instead of kzalloc and drop kfree(). Let the memory handled by driver detach.
Signed-off-by: Hsin-Yi Wang hsinyi@chromium.org Reviewed-by: Xin Ji xji@analogixsemi.com --- v2->v3: remove kfree() in anx7625_i2c_remove(). --- drivers/gpu/drm/bridge/analogix/anx7625.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 17b23940549a42..b7e3373994b480 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -2515,7 +2515,7 @@ static int anx7625_i2c_probe(struct i2c_client *client, return -ENODEV; }
- platform = kzalloc(sizeof(*platform), GFP_KERNEL); + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); if (!platform) { DRM_DEV_ERROR(dev, "fail to allocate driver data\n"); return -ENOMEM; @@ -2527,7 +2527,7 @@ static int anx7625_i2c_probe(struct i2c_client *client, if (ret) { if (ret != -EPROBE_DEFER) DRM_DEV_ERROR(dev, "fail to parse DT : %d\n", ret); - goto free_platform; + return ret; }
platform->client = client; @@ -2552,7 +2552,7 @@ static int anx7625_i2c_probe(struct i2c_client *client, if (!platform->hdcp_workqueue) { dev_err(dev, "fail to create work queue\n"); ret = -ENOMEM; - goto free_platform; + return ret; }
platform->pdata.intp_irq = client->irq; @@ -2637,9 +2637,6 @@ static int anx7625_i2c_probe(struct i2c_client *client, if (platform->hdcp_workqueue) destroy_workqueue(platform->hdcp_workqueue);
-free_platform: - kfree(platform); - return ret; }
@@ -2666,7 +2663,6 @@ static int anx7625_i2c_remove(struct i2c_client *client) if (platform->pdata.audio_en) anx7625_unregister_audio(platform);
- kfree(platform); return 0; }
Support reading edid through aux channel if panel is connected to aux bus. Extend anx7625_aux_dpcd_trans() to implement aux transfer function:
1. panel is populated in devm_of_dp_aux_populate_ep_devices(), so move anx7625_parse_dt() after. 2. Use pm runtime autosuspend since aux transfer function is called multiple times when reading edid. 3. No-op if aux transfer length is 0.
Signed-off-by: Hsin-Yi Wang hsinyi@chromium.org Reviewed-by: Xin Ji xji@analogixsemi.com --- v4->v5: fix header and indent.
v3->v4: rebase to latest drm-misc-next --- drivers/gpu/drm/bridge/analogix/anx7625.c | 120 ++++++++++++++++++---- drivers/gpu/drm/bridge/analogix/anx7625.h | 1 + 2 files changed, 103 insertions(+), 18 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index b7e3373994b480..a59a4f4d2c5b10 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -24,6 +24,7 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_crtc_helper.h> +#include <drm/dp/drm_dp_aux_bus.h> #include <drm/dp/drm_dp_helper.h> #include <drm/drm_edid.h> #include <drm/drm_hdcp.h> @@ -231,19 +232,23 @@ static int wait_aux_op_finish(struct anx7625_data *ctx) return 0; }
-static int anx7625_aux_dpcd_trans(struct anx7625_data *ctx, u8 op, - u32 address, u8 len, u8 *buf) +static int anx7625_aux_trans(struct anx7625_data *ctx, u8 op, u32 address, + u8 len, u8 *buf) { struct device *dev = &ctx->client->dev; int ret; u8 addrh, addrm, addrl; u8 cmd; + bool is_write = !(op & DP_AUX_I2C_READ);
- if (len > MAX_DPCD_BUFFER_SIZE) { + if (len > DP_AUX_MAX_PAYLOAD_BYTES) { dev_err(dev, "exceed aux buffer len.\n"); return -EINVAL; }
+ if (!len) + return len; + addrl = address & 0xFF; addrm = (address >> 8) & 0xFF; addrh = (address >> 16) & 0xFF; @@ -262,7 +267,7 @@ static int anx7625_aux_dpcd_trans(struct anx7625_data *ctx, u8 op, ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, AP_AUX_ADDR_19_16, addrh);
- if (op == DP_AUX_NATIVE_WRITE) + if (is_write) ret |= anx7625_reg_block_write(ctx, ctx->i2c.rx_p0_client, AP_AUX_BUFF_START, len, buf); /* Enable aux access */ @@ -275,14 +280,14 @@ static int anx7625_aux_dpcd_trans(struct anx7625_data *ctx, u8 op, }
ret = wait_aux_op_finish(ctx); - if (ret) { + if (ret < 0) { dev_err(dev, "aux IO error: wait aux op finish.\n"); return ret; }
/* Write done */ - if (op == DP_AUX_NATIVE_WRITE) - return 0; + if (is_write) + return len;
/* Read done, read out dpcd data */ ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client, @@ -292,7 +297,7 @@ static int anx7625_aux_dpcd_trans(struct anx7625_data *ctx, u8 op, return -EIO; }
- return 0; + return len; }
static int anx7625_video_mute_control(struct anx7625_data *ctx, @@ -867,7 +872,7 @@ static int anx7625_hdcp_enable(struct anx7625_data *ctx) }
/* Read downstream capability */ - anx7625_aux_dpcd_trans(ctx, DP_AUX_NATIVE_READ, 0x68028, 1, &bcap); + anx7625_aux_trans(ctx, DP_AUX_NATIVE_READ, 0x68028, 1, &bcap); if (!(bcap & 0x01)) { pr_warn("downstream not support HDCP 1.4, cap(%x).\n", bcap); return 0; @@ -956,7 +961,7 @@ static void anx7625_dp_stop(struct anx7625_data *ctx) dev_dbg(dev, "notify downstream enter into standby\n"); /* Downstream monitor enter into standby mode */ data = 2; - ret |= anx7625_aux_dpcd_trans(ctx, DP_AUX_NATIVE_WRITE, 0x000600, 1, &data); + ret |= anx7625_aux_trans(ctx, DP_AUX_NATIVE_WRITE, 0x000600, 1, &data); if (ret < 0) DRM_DEV_ERROR(dev, "IO error : mute video fail\n");
@@ -1655,11 +1660,56 @@ static int anx7625_parse_dt(struct device *dev, return 0; }
+static bool anx7625_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 inline struct anx7625_data *bridge_to_anx7625(struct drm_bridge *bridge) { return container_of(bridge, struct anx7625_data, bridge); }
+static ssize_t anx7625_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + struct anx7625_data *ctx = container_of(aux, struct anx7625_data, aux); + struct device *dev = &ctx->client->dev; + u8 request = msg->request & ~DP_AUX_I2C_MOT; + int ret = 0; + + pm_runtime_get_sync(dev); + msg->reply = 0; + switch (request) { + case DP_AUX_NATIVE_WRITE: + case DP_AUX_I2C_WRITE: + case DP_AUX_NATIVE_READ: + case DP_AUX_I2C_READ: + break; + default: + ret = -EINVAL; + } + if (!ret) + ret = anx7625_aux_trans(ctx, msg->request, msg->address, + msg->size, msg->buffer); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + return ret; +} + static struct edid *anx7625_get_edid(struct anx7625_data *ctx) { struct device *dev = &ctx->client->dev; @@ -2066,6 +2116,13 @@ static int anx7625_bridge_attach(struct drm_bridge *bridge, return -ENODEV; }
+ ctx->aux.drm_dev = bridge->dev; + err = drm_dp_aux_register(&ctx->aux); + if (err) { + dev_err(dev, "failed to register aux channel: %d\n", err); + return err; + } + if (ctx->pdata.panel_bridge) { err = drm_bridge_attach(bridge->encoder, ctx->pdata.panel_bridge, @@ -2079,6 +2136,13 @@ static int anx7625_bridge_attach(struct drm_bridge *bridge, return 0; }
+static void anx7625_bridge_detach(struct drm_bridge *bridge) +{ + struct anx7625_data *ctx = bridge_to_anx7625(bridge); + + drm_dp_aux_unregister(&ctx->aux); +} + static enum drm_mode_status anx7625_bridge_mode_valid(struct drm_bridge *bridge, const struct drm_display_info *info, @@ -2344,6 +2408,7 @@ static struct edid *anx7625_bridge_get_edid(struct drm_bridge *bridge,
static const struct drm_bridge_funcs anx7625_bridge_funcs = { .attach = anx7625_bridge_attach, + .detach = anx7625_bridge_detach, .mode_valid = anx7625_bridge_mode_valid, .mode_set = anx7625_bridge_mode_set, .atomic_check = anx7625_bridge_atomic_check, @@ -2501,6 +2566,12 @@ static const struct dev_pm_ops anx7625_pm_ops = { anx7625_runtime_pm_resume, NULL) };
+static void anx7625_runtime_disable(void *data) +{ + pm_runtime_dont_use_autosuspend(data); + pm_runtime_disable(data); +} + static int anx7625_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -2523,13 +2594,6 @@ static int anx7625_i2c_probe(struct i2c_client *client,
pdata = &platform->pdata;
- ret = anx7625_parse_dt(dev, pdata); - if (ret) { - if (ret != -EPROBE_DEFER) - DRM_DEV_ERROR(dev, "fail to parse DT : %d\n", ret); - return ret; - } - platform->client = client; i2c_set_clientdata(client, platform);
@@ -2577,6 +2641,19 @@ static int anx7625_i2c_probe(struct i2c_client *client, } }
+ platform->aux.name = "anx7625-aux"; + platform->aux.dev = dev; + platform->aux.transfer = anx7625_aux_transfer; + drm_dp_aux_init(&platform->aux); + devm_of_dp_aux_populate_ep_devices(&platform->aux); + + ret = anx7625_parse_dt(dev, pdata); + if (ret) { + if (ret != -EPROBE_DEFER) + DRM_DEV_ERROR(dev, "fail to parse DT : %d\n", ret); + return ret; + } + if (anx7625_register_i2c_dummy_clients(platform, client) != 0) { ret = -ENOMEM; DRM_DEV_ERROR(dev, "fail to reserve I2C bus.\n"); @@ -2584,6 +2661,12 @@ static int anx7625_i2c_probe(struct i2c_client *client, }
pm_runtime_enable(dev); + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + pm_suspend_ignore_children(dev, true); + ret = devm_add_action_or_reset(dev, anx7625_runtime_disable, dev); + if (ret) + return ret;
if (!platform->pdata.low_power_mode) { anx7625_disable_pd_protocol(platform); @@ -2596,7 +2679,8 @@ static int anx7625_i2c_probe(struct i2c_client *client,
platform->bridge.funcs = &anx7625_bridge_funcs; platform->bridge.of_node = client->dev.of_node; - platform->bridge.ops = DRM_BRIDGE_OP_EDID; + if (!anx7625_of_panel_on_aux_bus(&client->dev)) + platform->bridge.ops |= DRM_BRIDGE_OP_EDID; if (!platform->pdata.panel_bridge) platform->bridge.ops |= DRM_BRIDGE_OP_HPD | DRM_BRIDGE_OP_DETECT; diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h b/drivers/gpu/drm/bridge/analogix/anx7625.h index 64a8ab56529404..edbbfe410a56e8 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.h +++ b/drivers/gpu/drm/bridge/analogix/anx7625.h @@ -472,6 +472,7 @@ struct anx7625_data { u8 bridge_attached; struct drm_connector *connector; struct mipi_dsi_device *dsi; + struct drm_dp_aux aux; };
#endif /* __ANX7625_H__ */
Hi Hsin-Yi,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on drm-tip/drm-tip] [cannot apply to drm/drm-next robh/for-next drm-intel/for-linux-next v5.16 next-20220118] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Hsin-Yi-Wang/drm-bridge-anx7625-sen... base: git://anongit.freedesktop.org/drm/drm-tip drm-tip config: arm-randconfig-c002-20220118 (https://download.01.org/0day-ci/archive/20220120/202201200932.S1r1TWum-lkp@i...) compiler: arm-linux-gnueabi-gcc (GCC) 11.2.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/0day-ci/linux/commit/61809df270082584886188b067ee19744f4b... git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Hsin-Yi-Wang/drm-bridge-anx7625-send-DPCD-command-to-downstream/20220119-231952 git checkout 61809df270082584886188b067ee19744f4b35e1 # save the config file to linux build tree mkdir build_dir COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=arm SHELL=/bin/bash
If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot lkp@intel.com
All errors (new ones prefixed by >>):
arm-linux-gnueabi-ld: drivers/gpu/drm/bridge/analogix/anx7625.o: in function `anx7625_i2c_probe':
anx7625.c:(.text+0x1c10): undefined reference to `devm_of_dp_aux_populate_ep_devices'
--- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Hi Hsin-Yi,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on drm-tip/drm-tip] [cannot apply to drm/drm-next robh/for-next drm-intel/for-linux-next v5.16 next-20220118] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Hsin-Yi-Wang/drm-bridge-anx7625-sen... base: git://anongit.freedesktop.org/drm/drm-tip drm-tip config: i386-randconfig-r024-20220117 (https://download.01.org/0day-ci/archive/20220120/202201201223.sts9AtBC-lkp@i...) compiler: gcc-9 (Debian 9.3.0-22) 9.3.0 reproduce (this is a W=1 build): # https://github.com/0day-ci/linux/commit/61809df270082584886188b067ee19744f4b... git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Hsin-Yi-Wang/drm-bridge-anx7625-send-DPCD-command-to-downstream/20220119-231952 git checkout 61809df270082584886188b067ee19744f4b35e1 # save the config file to linux build tree mkdir build_dir make W=1 O=build_dir ARCH=i386 SHELL=/bin/bash
If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot lkp@intel.com
All errors (new ones prefixed by >>):
ld: drivers/gpu/drm/bridge/analogix/anx7625.o: in function `anx7625_i2c_probe':
drivers/gpu/drm/bridge/analogix/anx7625.c:2648: undefined reference to `devm_of_dp_aux_populate_ep_devices'
vim +2648 drivers/gpu/drm/bridge/analogix/anx7625.c
2574 2575 static int anx7625_i2c_probe(struct i2c_client *client, 2576 const struct i2c_device_id *id) 2577 { 2578 struct anx7625_data *platform; 2579 struct anx7625_platform_data *pdata; 2580 int ret = 0; 2581 struct device *dev = &client->dev; 2582 2583 if (!i2c_check_functionality(client->adapter, 2584 I2C_FUNC_SMBUS_I2C_BLOCK)) { 2585 DRM_DEV_ERROR(dev, "anx7625's i2c bus doesn't support\n"); 2586 return -ENODEV; 2587 } 2588 2589 platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); 2590 if (!platform) { 2591 DRM_DEV_ERROR(dev, "fail to allocate driver data\n"); 2592 return -ENOMEM; 2593 } 2594 2595 pdata = &platform->pdata; 2596 2597 platform->client = client; 2598 i2c_set_clientdata(client, platform); 2599 2600 pdata->supplies[0].supply = "vdd10"; 2601 pdata->supplies[1].supply = "vdd18"; 2602 pdata->supplies[2].supply = "vdd33"; 2603 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(pdata->supplies), 2604 pdata->supplies); 2605 if (ret) { 2606 DRM_DEV_ERROR(dev, "fail to get power supplies: %d\n", ret); 2607 return ret; 2608 } 2609 anx7625_init_gpio(platform); 2610 2611 mutex_init(&platform->lock); 2612 mutex_init(&platform->hdcp_wq_lock); 2613 2614 INIT_DELAYED_WORK(&platform->hdcp_work, hdcp_check_work_func); 2615 platform->hdcp_workqueue = create_workqueue("hdcp workqueue"); 2616 if (!platform->hdcp_workqueue) { 2617 dev_err(dev, "fail to create work queue\n"); 2618 ret = -ENOMEM; 2619 return ret; 2620 } 2621 2622 platform->pdata.intp_irq = client->irq; 2623 if (platform->pdata.intp_irq) { 2624 INIT_WORK(&platform->work, anx7625_work_func); 2625 platform->workqueue = alloc_workqueue("anx7625_work", 2626 WQ_FREEZABLE | WQ_MEM_RECLAIM, 1); 2627 if (!platform->workqueue) { 2628 DRM_DEV_ERROR(dev, "fail to create work queue\n"); 2629 ret = -ENOMEM; 2630 goto free_hdcp_wq; 2631 } 2632 2633 ret = devm_request_threaded_irq(dev, platform->pdata.intp_irq, 2634 NULL, anx7625_intr_hpd_isr, 2635 IRQF_TRIGGER_FALLING | 2636 IRQF_ONESHOT, 2637 "anx7625-intp", platform); 2638 if (ret) { 2639 DRM_DEV_ERROR(dev, "fail to request irq\n"); 2640 goto free_wq; 2641 } 2642 } 2643 2644 platform->aux.name = "anx7625-aux"; 2645 platform->aux.dev = dev; 2646 platform->aux.transfer = anx7625_aux_transfer; 2647 drm_dp_aux_init(&platform->aux);
2648 devm_of_dp_aux_populate_ep_devices(&platform->aux);
2649 2650 ret = anx7625_parse_dt(dev, pdata); 2651 if (ret) { 2652 if (ret != -EPROBE_DEFER) 2653 DRM_DEV_ERROR(dev, "fail to parse DT : %d\n", ret); 2654 return ret; 2655 } 2656 2657 if (anx7625_register_i2c_dummy_clients(platform, client) != 0) { 2658 ret = -ENOMEM; 2659 DRM_DEV_ERROR(dev, "fail to reserve I2C bus.\n"); 2660 goto free_wq; 2661 } 2662 2663 pm_runtime_enable(dev); 2664 pm_runtime_set_autosuspend_delay(dev, 1000); 2665 pm_runtime_use_autosuspend(dev); 2666 pm_suspend_ignore_children(dev, true); 2667 ret = devm_add_action_or_reset(dev, anx7625_runtime_disable, dev); 2668 if (ret) 2669 return ret; 2670 2671 if (!platform->pdata.low_power_mode) { 2672 anx7625_disable_pd_protocol(platform); 2673 pm_runtime_get_sync(dev); 2674 } 2675 2676 /* Add work function */ 2677 if (platform->pdata.intp_irq) 2678 queue_work(platform->workqueue, &platform->work); 2679 2680 platform->bridge.funcs = &anx7625_bridge_funcs; 2681 platform->bridge.of_node = client->dev.of_node; 2682 if (!anx7625_of_panel_on_aux_bus(&client->dev)) 2683 platform->bridge.ops |= DRM_BRIDGE_OP_EDID; 2684 if (!platform->pdata.panel_bridge) 2685 platform->bridge.ops |= DRM_BRIDGE_OP_HPD | 2686 DRM_BRIDGE_OP_DETECT; 2687 platform->bridge.type = platform->pdata.panel_bridge ? 2688 DRM_MODE_CONNECTOR_eDP : 2689 DRM_MODE_CONNECTOR_DisplayPort; 2690 2691 drm_bridge_add(&platform->bridge); 2692 2693 if (!platform->pdata.is_dpi) { 2694 ret = anx7625_attach_dsi(platform); 2695 if (ret) { 2696 DRM_DEV_ERROR(dev, "Fail to attach to dsi : %d\n", ret); 2697 goto unregister_bridge; 2698 } 2699 } 2700 2701 if (platform->pdata.audio_en) 2702 anx7625_register_audio(dev, platform); 2703 2704 DRM_DEV_DEBUG_DRIVER(dev, "probe done\n"); 2705 2706 return 0; 2707 2708 unregister_bridge: 2709 drm_bridge_remove(&platform->bridge); 2710 2711 if (!platform->pdata.low_power_mode) 2712 pm_runtime_put_sync_suspend(&client->dev); 2713 2714 anx7625_unregister_i2c_dummy_clients(platform); 2715 2716 free_wq: 2717 if (platform->workqueue) 2718 destroy_workqueue(platform->workqueue); 2719 2720 free_hdcp_wq: 2721 if (platform->hdcp_workqueue) 2722 destroy_workqueue(platform->hdcp_workqueue); 2723 2724 return ret; 2725 } 2726
--- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
List panel under aux-bus node if it's connected to anx7625's aux bus.
Signed-off-by: Hsin-Yi Wang hsinyi@chromium.org Reviewed-by: Xin Ji xji@analogixsemi.com --- .../display/bridge/analogix,anx7625.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml index 1d3e88daca041a..0d38d6fe39830f 100644 --- a/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml +++ b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml @@ -83,6 +83,9 @@ properties: type: boolean description: let the driver enable audio HDMI codec function or not.
+ aux-bus: + $ref: /schemas/display/dp-aux-bus.yaml# + ports: $ref: /schemas/graph.yaml#/properties/ports
@@ -167,5 +170,19 @@ examples: }; }; }; + + aux-bus { + panel { + compatible = "innolux,n125hce-gn1"; + power-supply = <&pp3300_disp_x>; + backlight = <&backlight_lcd0>; + + port { + panel_in: endpoint { + remote-endpoint = <&anx7625_out>; + }; + }; + }; + }; }; };
Hey Hsin-Yi,
While I can review this patch, I don't have the authority to merge it since it is outside the scope of my maintainership. Rob Herring, Daniel Vetter or David Airlie would have to Ack this patch.
On Wed, 19 Jan 2022 at 16:18, Hsin-Yi Wang hsinyi@chromium.org wrote:
List panel under aux-bus node if it's connected to anx7625's aux bus.
Signed-off-by: Hsin-Yi Wang hsinyi@chromium.org Reviewed-by: Xin Ji xji@analogixsemi.com
.../display/bridge/analogix,anx7625.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml index 1d3e88daca041a..0d38d6fe39830f 100644 --- a/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml +++ b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml @@ -83,6 +83,9 @@ properties: type: boolean description: let the driver enable audio HDMI codec function or not.
- aux-bus:
- $ref: /schemas/display/dp-aux-bus.yaml#
- ports: $ref: /schemas/graph.yaml#/properties/ports
@@ -167,5 +170,19 @@ examples: }; }; };
aux-bus {
panel {
compatible = "innolux,n125hce-gn1";
power-supply = <&pp3300_disp_x>;
backlight = <&backlight_lcd0>;
port {
panel_in: endpoint {
remote-endpoint = <&anx7625_out>;
};
};
};
};}; };
-- 2.34.1.703.g22d0c6ccf7-goog
On Wed, Jan 19, 2022 at 11:36 PM Robert Foss robert.foss@linaro.org wrote:
Hey Hsin-Yi,
While I can review this patch, I don't have the authority to merge it since it is outside the scope of my maintainership. Rob Herring, Daniel Vetter or David Airlie would have to Ack this patch.
hi Rob,
Can you help ack this patch? thanks
On Wed, 19 Jan 2022 at 16:18, Hsin-Yi Wang hsinyi@chromium.org wrote:
List panel under aux-bus node if it's connected to anx7625's aux bus.
Signed-off-by: Hsin-Yi Wang hsinyi@chromium.org Reviewed-by: Xin Ji xji@analogixsemi.com
.../display/bridge/analogix,anx7625.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml index 1d3e88daca041a..0d38d6fe39830f 100644 --- a/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml +++ b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml @@ -83,6 +83,9 @@ properties: type: boolean description: let the driver enable audio HDMI codec function or not.
- aux-bus:
- $ref: /schemas/display/dp-aux-bus.yaml#
- ports: $ref: /schemas/graph.yaml#/properties/ports
@@ -167,5 +170,19 @@ examples: }; }; };
aux-bus {
panel {
compatible = "innolux,n125hce-gn1";
power-supply = <&pp3300_disp_x>;
backlight = <&backlight_lcd0>;
port {
panel_in: endpoint {
remote-endpoint = <&anx7625_out>;
};
};
};
};}; };
-- 2.34.1.703.g22d0c6ccf7-goog
On Tue, Jan 25, 2022 at 2:25 PM Hsin-Yi Wang hsinyi@chromium.org wrote:
On Wed, Jan 19, 2022 at 11:36 PM Robert Foss robert.foss@linaro.org wrote:
Hey Hsin-Yi,
While I can review this patch, I don't have the authority to merge it since it is outside the scope of my maintainership. Rob Herring, Daniel Vetter or David Airlie would have to Ack this patch.
hi Rob, Daniel, and David,
Can you help ack this patch?
Thanks
On Wed, 19 Jan 2022 at 16:18, Hsin-Yi Wang hsinyi@chromium.org wrote:
List panel under aux-bus node if it's connected to anx7625's aux bus.
Signed-off-by: Hsin-Yi Wang hsinyi@chromium.org Reviewed-by: Xin Ji xji@analogixsemi.com
.../display/bridge/analogix,anx7625.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml index 1d3e88daca041a..0d38d6fe39830f 100644 --- a/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml +++ b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml @@ -83,6 +83,9 @@ properties: type: boolean description: let the driver enable audio HDMI codec function or not.
- aux-bus:
- $ref: /schemas/display/dp-aux-bus.yaml#
- ports: $ref: /schemas/graph.yaml#/properties/ports
@@ -167,5 +170,19 @@ examples: }; }; };
aux-bus {
panel {
compatible = "innolux,n125hce-gn1";
power-supply = <&pp3300_disp_x>;
backlight = <&backlight_lcd0>;
port {
panel_in: endpoint {
remote-endpoint = <&anx7625_out>;
};
};
};
};}; };
-- 2.34.1.703.g22d0c6ccf7-goog
On Wed, 19 Jan 2022 at 16:17, Hsin-Yi Wang hsinyi@chromium.org wrote:
From: Xin Ji xji@analogixsemi.com
Send DPCD command to downstream before anx7625 power down, let downstream monitor enter into standby mode.
Signed-off-by: Xin Ji xji@analogixsemi.com Signed-off-by: Hsin-Yi Wang hsinyi@chromium.org
Hsin-Yi: Can you supply a r-b tag to this patch if it looks good to you?
v3->v4: Use common DP_AUX_NATIVE_READ/WRITE
Previously in: https://patchwork.kernel.org/project/dri-devel/patch/1f36f8bf0a48fb2bba17bac...
drivers/gpu/drm/bridge/analogix/anx7625.c | 42 +++++++++++++++++++---- drivers/gpu/drm/bridge/analogix/anx7625.h | 2 -- 2 files changed, 35 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 76662fce4ce61d..17b23940549a42 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -129,6 +129,23 @@ static int anx7625_reg_write(struct anx7625_data *ctx, return ret; }
+static int anx7625_reg_block_write(struct anx7625_data *ctx,
struct i2c_client *client,
u8 reg_addr, u8 len, u8 *buf)
+{
int ret;
struct device *dev = &client->dev;
i2c_access_workaround(ctx, client);
ret = i2c_smbus_write_i2c_block_data(client, reg_addr, len, buf);
if (ret < 0)
dev_err(dev, "write i2c block failed id=%x\n:%x",
client->addr, reg_addr);
return ret;
+}
static int anx7625_write_or(struct anx7625_data *ctx, struct i2c_client *client, u8 offset, u8 mask) @@ -214,8 +231,8 @@ static int wait_aux_op_finish(struct anx7625_data *ctx) return 0; }
-static int anx7625_aux_dpcd_read(struct anx7625_data *ctx,
u32 address, u8 len, u8 *buf)
+static int anx7625_aux_dpcd_trans(struct anx7625_data *ctx, u8 op,
u32 address, u8 len, u8 *buf)
{ struct device *dev = &ctx->client->dev; int ret; @@ -231,8 +248,7 @@ static int anx7625_aux_dpcd_read(struct anx7625_data *ctx, addrm = (address >> 8) & 0xFF; addrh = (address >> 16) & 0xFF;
cmd = DPCD_CMD(len, DPCD_READ);
cmd = ((len - 1) << 4) | 0x09;
cmd = DPCD_CMD(len, op); /* Set command and length */ ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
@@ -246,6 +262,9 @@ static int anx7625_aux_dpcd_read(struct anx7625_data *ctx, ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, AP_AUX_ADDR_19_16, addrh);
if (op == DP_AUX_NATIVE_WRITE)
ret |= anx7625_reg_block_write(ctx, ctx->i2c.rx_p0_client,
AP_AUX_BUFF_START, len, buf); /* Enable aux access */ ret |= anx7625_write_or(ctx, ctx->i2c.rx_p0_client, AP_AUX_CTRL_STATUS, AP_AUX_CTRL_OP_EN);
@@ -255,14 +274,17 @@ static int anx7625_aux_dpcd_read(struct anx7625_data *ctx, return -EIO; }
usleep_range(2000, 2100);
ret = wait_aux_op_finish(ctx); if (ret) { dev_err(dev, "aux IO error: wait aux op finish.\n"); return ret; }
/* Write done */
if (op == DP_AUX_NATIVE_WRITE)
return 0;
/* Read done, read out dpcd data */ ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client, AP_AUX_BUFF_START, len, buf); if (ret < 0) {
@@ -845,7 +867,7 @@ static int anx7625_hdcp_enable(struct anx7625_data *ctx) }
/* Read downstream capability */
anx7625_aux_dpcd_read(ctx, 0x68028, 1, &bcap);
anx7625_aux_dpcd_trans(ctx, DP_AUX_NATIVE_READ, 0x68028, 1, &bcap); if (!(bcap & 0x01)) { pr_warn("downstream not support HDCP 1.4, cap(%x).\n", bcap); return 0;
@@ -918,6 +940,7 @@ static void anx7625_dp_stop(struct anx7625_data *ctx) { struct device *dev = &ctx->client->dev; int ret;
u8 data; DRM_DEV_DEBUG_DRIVER(dev, "stop dp output\n");
@@ -929,6 +952,11 @@ static void anx7625_dp_stop(struct anx7625_data *ctx) ret |= anx7625_write_and(ctx, ctx->i2c.tx_p2_client, 0x08, 0x7f);
ret |= anx7625_video_mute_control(ctx, 1);
dev_dbg(dev, "notify downstream enter into standby\n");
/* Downstream monitor enter into standby mode */
data = 2;
ret |= anx7625_aux_dpcd_trans(ctx, DP_AUX_NATIVE_WRITE, 0x000600, 1, &data); if (ret < 0) DRM_DEV_ERROR(dev, "IO error : mute video fail\n");
diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h b/drivers/gpu/drm/bridge/analogix/anx7625.h index 56165f5b254c14..64a8ab56529404 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.h +++ b/drivers/gpu/drm/bridge/analogix/anx7625.h @@ -242,8 +242,6 @@
#define AP_AUX_COMMAND 0x27 /* com+len */ #define LENGTH_SHIFT 4 -#define DPCD_READ 0x09 -#define DPCD_WRITE 0x08 #define DPCD_CMD(len, cmd) ((((len) - 1) << LENGTH_SHIFT) | (cmd))
/* Bit 0&1: 3D video structure */
2.34.1.703.g22d0c6ccf7-goog
On Wed, Jan 19, 2022 at 11:38 PM Robert Foss robert.foss@linaro.org wrote:
On Wed, 19 Jan 2022 at 16:17, Hsin-Yi Wang hsinyi@chromium.org wrote:
From: Xin Ji xji@analogixsemi.com
Send DPCD command to downstream before anx7625 power down, let downstream monitor enter into standby mode.
Signed-off-by: Xin Ji xji@analogixsemi.com Signed-off-by: Hsin-Yi Wang hsinyi@chromium.org
Reviewed-by: Hsin-Yi Wang hsinyi@chromium.org
Hsin-Yi: Can you supply a r-b tag to this patch if it looks good to you?
v3->v4: Use common DP_AUX_NATIVE_READ/WRITE
Previously in: https://patchwork.kernel.org/project/dri-devel/patch/1f36f8bf0a48fb2bba17bac...
drivers/gpu/drm/bridge/analogix/anx7625.c | 42 +++++++++++++++++++---- drivers/gpu/drm/bridge/analogix/anx7625.h | 2 -- 2 files changed, 35 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 76662fce4ce61d..17b23940549a42 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -129,6 +129,23 @@ static int anx7625_reg_write(struct anx7625_data *ctx, return ret; }
+static int anx7625_reg_block_write(struct anx7625_data *ctx,
struct i2c_client *client,
u8 reg_addr, u8 len, u8 *buf)
+{
int ret;
struct device *dev = &client->dev;
i2c_access_workaround(ctx, client);
ret = i2c_smbus_write_i2c_block_data(client, reg_addr, len, buf);
if (ret < 0)
dev_err(dev, "write i2c block failed id=%x\n:%x",
client->addr, reg_addr);
return ret;
+}
static int anx7625_write_or(struct anx7625_data *ctx, struct i2c_client *client, u8 offset, u8 mask) @@ -214,8 +231,8 @@ static int wait_aux_op_finish(struct anx7625_data *ctx) return 0; }
-static int anx7625_aux_dpcd_read(struct anx7625_data *ctx,
u32 address, u8 len, u8 *buf)
+static int anx7625_aux_dpcd_trans(struct anx7625_data *ctx, u8 op,
u32 address, u8 len, u8 *buf)
{ struct device *dev = &ctx->client->dev; int ret; @@ -231,8 +248,7 @@ static int anx7625_aux_dpcd_read(struct anx7625_data *ctx, addrm = (address >> 8) & 0xFF; addrh = (address >> 16) & 0xFF;
cmd = DPCD_CMD(len, DPCD_READ);
cmd = ((len - 1) << 4) | 0x09;
cmd = DPCD_CMD(len, op); /* Set command and length */ ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
@@ -246,6 +262,9 @@ static int anx7625_aux_dpcd_read(struct anx7625_data *ctx, ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, AP_AUX_ADDR_19_16, addrh);
if (op == DP_AUX_NATIVE_WRITE)
ret |= anx7625_reg_block_write(ctx, ctx->i2c.rx_p0_client,
AP_AUX_BUFF_START, len, buf); /* Enable aux access */ ret |= anx7625_write_or(ctx, ctx->i2c.rx_p0_client, AP_AUX_CTRL_STATUS, AP_AUX_CTRL_OP_EN);
@@ -255,14 +274,17 @@ static int anx7625_aux_dpcd_read(struct anx7625_data *ctx, return -EIO; }
usleep_range(2000, 2100);
ret = wait_aux_op_finish(ctx); if (ret) { dev_err(dev, "aux IO error: wait aux op finish.\n"); return ret; }
/* Write done */
if (op == DP_AUX_NATIVE_WRITE)
return 0;
/* Read done, read out dpcd data */ ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client, AP_AUX_BUFF_START, len, buf); if (ret < 0) {
@@ -845,7 +867,7 @@ static int anx7625_hdcp_enable(struct anx7625_data *ctx) }
/* Read downstream capability */
anx7625_aux_dpcd_read(ctx, 0x68028, 1, &bcap);
anx7625_aux_dpcd_trans(ctx, DP_AUX_NATIVE_READ, 0x68028, 1, &bcap); if (!(bcap & 0x01)) { pr_warn("downstream not support HDCP 1.4, cap(%x).\n", bcap); return 0;
@@ -918,6 +940,7 @@ static void anx7625_dp_stop(struct anx7625_data *ctx) { struct device *dev = &ctx->client->dev; int ret;
u8 data; DRM_DEV_DEBUG_DRIVER(dev, "stop dp output\n");
@@ -929,6 +952,11 @@ static void anx7625_dp_stop(struct anx7625_data *ctx) ret |= anx7625_write_and(ctx, ctx->i2c.tx_p2_client, 0x08, 0x7f);
ret |= anx7625_video_mute_control(ctx, 1);
dev_dbg(dev, "notify downstream enter into standby\n");
/* Downstream monitor enter into standby mode */
data = 2;
ret |= anx7625_aux_dpcd_trans(ctx, DP_AUX_NATIVE_WRITE, 0x000600, 1, &data); if (ret < 0) DRM_DEV_ERROR(dev, "IO error : mute video fail\n");
diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h b/drivers/gpu/drm/bridge/analogix/anx7625.h index 56165f5b254c14..64a8ab56529404 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.h +++ b/drivers/gpu/drm/bridge/analogix/anx7625.h @@ -242,8 +242,6 @@
#define AP_AUX_COMMAND 0x27 /* com+len */ #define LENGTH_SHIFT 4 -#define DPCD_READ 0x09 -#define DPCD_WRITE 0x08 #define DPCD_CMD(len, cmd) ((((len) - 1) << LENGTH_SHIFT) | (cmd))
/* Bit 0&1: 3D video structure */
2.34.1.703.g22d0c6ccf7-goog
dri-devel@lists.freedesktop.org