drm/bridge: anx7625: Convert to use devm_kzalloc
Subsystems (4)
PATCH 1/3 drm/bridge: anx7625: Convert to use devm_kzalloc
Use devm_kzalloc instead of kzalloc and drop kfree(). Let the memory handled by driver detach.
--- drivers/gpu/drm/bridge/analogix/anx7625.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)
drivers/gpu/drm/bridge/analogix/anx7625.c +3 -6
@@ -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; }
Signature · 1 line
2.34.1.575.g55b058a8bb-goog
PATCH 2/3 drm/bridge: anx7625: Support reading edid through aux channel
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.
---
This patch is based on drm-misc-next and depends on
https://patchwork.freedesktop.org/patch/469081/
--- drivers/gpu/drm/bridge/analogix/anx7625.c | 123 ++++++++++++++++++---- drivers/gpu/drm/bridge/analogix/anx7625.h | 4 + 2 files changed, 109 insertions(+), 18 deletions(-)
drivers/gpu/drm/bridge/analogix/anx7625.c +105 -18
@@ -24,6 +24,7 @@#include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_dp_aux_bus.h> #include <drm/drm_dp_helper.h> #include <drm/drm_edid.h> #include <drm/drm_hdcp.h>
@@ -231,19 +232,22 @@ 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; -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 +266,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 ==DPCD_WRITE ) +if (op ==DPCD_WRITE || op ==AP_AUX_WRITE ) ret |=anx7625_reg_block_write (ctx, ctx->i2c.rx_p0_client,AP_AUX_BUFF_START , len, buf);/* Enable aux access */
@@ -275,14 +279,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 ==DPCD_WRITE ) -return 0 ; +if (op ==DPCD_WRITE || op ==AP_AUX_WRITE ) +return len;/* Read done, read out dpcd data */ ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client,
@@ -292,7 +296,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 +871,7 @@ static int anx7625_hdcp_enable(struct anx7625_data *ctx) }/* Read downstream capability */ -anx7625_aux_dpcd_trans (ctx,DPCD_READ ,0x68028 ,1 , &bcap); +anx7625_aux_trans (ctx,DPCD_READ ,0x68028 ,1 , &bcap);if (!(bcap &0x01 )) {pr_warn ("downstream not support HDCP 1.4, cap(%x).\n" , bcap);return 0 ;
@@ -956,7 +960,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,DPCD_WRITE ,0x000600 ,1 , &data); + ret |=anx7625_aux_trans (ctx,DPCD_WRITE ,0x000600 ,1 , &data);if (ret <0 )DRM_DEV_ERROR (dev,"IO error : mute video fail\n" );
@@ -1655,11 +1659,60 @@ 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 , op; +int ret =0 ; + +pm_runtime_get_sync (dev); + msg->reply =0 ; +switch (request) { +case DP_AUX_NATIVE_WRITE : +case DP_AUX_I2C_WRITE : + op =AP_AUX_WRITE ; +break ; +case DP_AUX_NATIVE_READ : +case DP_AUX_I2C_READ : + op =AP_AUX_READ ; +break ; +default : + ret = -EINVAL ; + } +if (!ret) { + ret =anx7625_aux_trans (ctx, op, 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 +2119,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 +2139,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 +2411,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 +2569,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 +2597,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 +2644,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 +2664,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 +2682,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 ;
drivers/gpu/drm/bridge/analogix/anx7625.h +4 -0
@@ -231,6 +231,9 @@#define AP_AUX_ADDR_15_8 0x12#define AP_AUX_ADDR_19_16 0x13 +#define AP_AUX_READ 0x1 +#define AP_AUX_WRITE 0x4 +/* Bit[0:3] AUX status, bit 4 op_en, bit 5 address only */ #define AP_AUX_CTRL_STATUS 0x14#define AP_AUX_CTRL_OP_EN 0x10
@@ -474,6 +477,7 @@ struct anx7625_data {u8 bridge_attached;struct drm_connector *connector;struct mipi_dsi_device *dsi; + struct drm_dp_aux aux; };#endif /* __ANX7625_H__ */
Signature · 1 line
2.34.1.575.g55b058a8bb-goog
Re: [PATCH 2/3] drm/bridge: anx7625: Support reading edid through aux channel
Hi Hsin-Yi, thanks for the patch! Please fix the follow comment, then add my id.
Quoted 38 lines · Hsin-Yi Wang
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 moveanx7625_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 <[email protected]>---
This patch is based on drm-misc-next and depends on
https://patchwork.freedesktop.org/patch/469081/--- drivers/gpu/drm/bridge/analogix/anx7625.c | 123 ++++++++++++++++++---- drivers/gpu/drm/bridge/analogix/anx7625.h | 4 + 2 files changed, 109 insertions(+), 18 deletions(-)drivers/gpu/drm/bridge/analogix/anx7625.c +3
-2@@ -24,6 +24,7 @@#include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_dp_aux_bus.h> #include <drm/drm_dp_helper.h> #include <drm/drm_edid.h> #include <drm/drm_hdcp.h> @@ -231,19 +232,22 @@ 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)
drivers/gpu/drm/bridge/analogix/anx7625.c static int wait_aux_op_finish(struct anx7625_data *ctx) · line 245
Quoted 10 lines
drivers/gpu/drm/bridge/analogix/anx7625.c +1
-1{struct device *dev = &ctx->client->dev;int ret;u8 addrh, addrm, addrl;u8 cmd; -if (len >MAX_DPCD_BUFFER_SIZE ) { +if (len >DP_AUX_MAX_PAYLOAD_BYTES ) {dev_err (dev,"exceed aux buffer len.\n" );return -EINVAL ;
The native write command is 0x08, I2C Over aux write command is 0x04. The native read command is 0x09, I2C Over aux read command is 0x05.
Quoted 92 lines
drivers/gpu/drm/bridge/analogix/anx7625.c +31
-7} +if (!len) +return len; + addrl = address &0xFF ; addrm = (address >>8 ) &0xFF ; addrh = (address >>16 ) &0xFF ;@@ -262,7 +266,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 ==DPCD_WRITE ) +if (op ==DPCD_WRITE || op ==AP_AUX_WRITE ) ret |=anx7625_reg_block_write (ctx, ctx->i2c.rx_p0_client,AP_AUX_BUFF_START , len, buf);/* Enable aux access */ @@ -275,14 +279,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 ==DPCD_WRITE ) -return 0 ; +if (op ==DPCD_WRITE || op ==AP_AUX_WRITE ) +return len;/* Read done, read out dpcd data */ ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client,@@ -292,7 +296,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 +871,7 @@ static int anx7625_hdcp_enable(struct anx7625_data *ctx) }/* Read downstream capability */ -anx7625_aux_dpcd_trans (ctx,DPCD_READ ,0x68028 ,1 , &bcap); +anx7625_aux_trans (ctx,DPCD_READ ,0x68028 ,1 , &bcap);if (!(bcap &0x01 )) {pr_warn ("downstream not support HDCP 1.4, cap(%x).\n" , bcap);return 0 ;@@ -956,7 +960,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,DPCD_WRITE ,0x000600 ,1 , &data); + ret |=anx7625_aux_trans (ctx,DPCD_WRITE ,0x000600 ,1 , &data);if (ret <0 )DRM_DEV_ERROR (dev,"IO error : mute video fail\n" );@@ -1655,11 +1659,60 @@ 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);
drivers/gpu/drm/bridge/analogix/anx7625.c static int anx7625_parse_dt(struct device *dev, · line 1697
Quoted 10 lines
drivers/gpu/drm/bridge/analogix/anx7625.c +10
-0+struct device *dev = &ctx->client->dev; +u8 request = msg->request & ~DP_AUX_I2C_MOT , op; +int ret =0 ; + +pm_runtime_get_sync (dev); + msg->reply =0 ; +switch (request) { +case DP_AUX_NATIVE_WRITE : +case DP_AUX_I2C_WRITE : + op =AP_AUX_WRITE ;
The DPCD native write is different with I2C over aux write.
drivers/gpu/drm/bridge/analogix/anx7625.c static int anx7625_parse_dt(struct device *dev, · line 1701
Quoted 4 lines
drivers/gpu/drm/bridge/analogix/anx7625.c +4
-0+break ; +case DP_AUX_NATIVE_READ : +case DP_AUX_I2C_READ : + op =AP_AUX_READ ;
The DPCD native read is different with I2C over aux read.
Quoted 147 lines
drivers/gpu/drm/bridge/analogix/anx7625.c +56
-8+break ; +default : + ret = -EINVAL ; + } +if (!ret) { + ret =anx7625_aux_trans (ctx, op, 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 +2119,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 +2139,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 +2411,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 +2569,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 +2597,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 +2644,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 +2664,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 +2682,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 ;drivers/gpu/drm/bridge/analogix/anx7625.h +4
-0@@ -231,6 +231,9 @@#define AP_AUX_ADDR_15_8 0x12#define AP_AUX_ADDR_19_16 0x13 +#define AP_AUX_READ 0x1 +#define AP_AUX_WRITE 0x4 +/* Bit[0:3] AUX status, bit 4 op_en, bit 5 address only */ #define AP_AUX_CTRL_STATUS 0x14#define AP_AUX_CTRL_OP_EN 0x10@@ -474,6 +477,7 @@ struct anx7625_data {u8 bridge_attached;struct drm_connector *connector;struct mipi_dsi_device *dsi; + struct drm_dp_aux aux; };#endif /* __ANX7625_H__ */ Signature · 1 line
2.34.1.575.g55b058a8bb-goog
Re: [PATCH 2/3] drm/bridge: anx7625: Support reading edid through aux channel
Quoted 50 lines · Xin Ji
Hi Hsin-Yi, thanks for the patch! Please fix the follow comment, then add my id.
Reviewed-by Xin Ji <[email protected]>Quoted 44 lines · Hsin-Yi Wang
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 moveanx7625_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 <[email protected]>---
This patch is based on drm-misc-next and depends on
https://patchwork.freedesktop.org/patch/469081/--- drivers/gpu/drm/bridge/analogix/anx7625.c | 123 ++++++++++++++++++---- drivers/gpu/drm/bridge/analogix/anx7625.h | 4 + 2 files changed, 109 insertions(+), 18 deletions(-)drivers/gpu/drm/bridge/analogix/anx7625.c +3
-2@@ -24,6 +24,7 @@#include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_dp_aux_bus.h> #include <drm/drm_dp_helper.h> #include <drm/drm_edid.h> #include <drm/drm_hdcp.h> @@ -231,19 +232,22 @@ 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;
Quoted 7 lines
drivers/gpu/drm/bridge/analogix/anx7625.c static int wait_aux_op_finish(struct anx7625_data *ctx) · line 245
Quoted 4 lines
drivers/gpu/drm/bridge/analogix/anx7625.c +1
-1-if (len >MAX_DPCD_BUFFER_SIZE ) { +if (len >DP_AUX_MAX_PAYLOAD_BYTES ) {dev_err (dev,"exceed aux buffer len.\n" );return -EINVAL ;The native write command is
0x08, I2C Over aux write command is0x04. The native read command is0x09, I2C Over aux read command is0x05.
Thanks for the review, the command for native read/write is updated.
v2 is sent.
Quoted 258 lines
Quoted 93 lines
drivers/gpu/drm/bridge/analogix/anx7625.c +31
-7} +if (!len) +return len; + addrl = address &0xFF ; addrm = (address >>8 ) &0xFF ; addrh = (address >>16 ) &0xFF ;@@ -262,7 +266,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 ==DPCD_WRITE ) +if (op ==DPCD_WRITE || op ==AP_AUX_WRITE ) ret |=anx7625_reg_block_write (ctx, ctx->i2c.rx_p0_client,AP_AUX_BUFF_START , len, buf);/* Enable aux access */ @@ -275,14 +279,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 ==DPCD_WRITE ) -return 0 ; +if (op ==DPCD_WRITE || op ==AP_AUX_WRITE ) +return len;/* Read done, read out dpcd data */ ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client,@@ -292,7 +296,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 +871,7 @@ static int anx7625_hdcp_enable(struct anx7625_data *ctx) }/* Read downstream capability */ -anx7625_aux_dpcd_trans (ctx,DPCD_READ ,0x68028 ,1 , &bcap); +anx7625_aux_trans (ctx,DPCD_READ ,0x68028 ,1 , &bcap);if (!(bcap &0x01 )) {pr_warn ("downstream not support HDCP 1.4, cap(%x).\n" , bcap);return 0 ;@@ -956,7 +960,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,DPCD_WRITE ,0x000600 ,1 , &data); + ret |=anx7625_aux_trans (ctx,DPCD_WRITE ,0x000600 ,1 , &data);if (ret <0 )DRM_DEV_ERROR (dev,"IO error : mute video fail\n" );@@ -1655,11 +1659,60 @@ 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);drivers/gpu/drm/bridge/analogix/anx7625.c static int anx7625_parse_dt(struct device *dev, · line 1697
Quoted 10 lines
drivers/gpu/drm/bridge/analogix/anx7625.c +10
-0+struct device *dev = &ctx->client->dev; +u8 request = msg->request & ~DP_AUX_I2C_MOT , op; +int ret =0 ; + +pm_runtime_get_sync (dev); + msg->reply =0 ; +switch (request) { +case DP_AUX_NATIVE_WRITE : +case DP_AUX_I2C_WRITE : + op =AP_AUX_WRITE ;The DPCD native write is different with I2C over aux write.
drivers/gpu/drm/bridge/analogix/anx7625.c static int anx7625_parse_dt(struct device *dev, · line 1701
Quoted 4 lines
drivers/gpu/drm/bridge/analogix/anx7625.c +4
-0+break ; +case DP_AUX_NATIVE_READ : +case DP_AUX_I2C_READ : + op =AP_AUX_READ ;The DPCD native read is different with I2C over aux read.
Quoted 147 lines
drivers/gpu/drm/bridge/analogix/anx7625.c +56
-8+break ; +default : + ret = -EINVAL ; + } +if (!ret) { + ret =anx7625_aux_trans (ctx, op, 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 +2119,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 +2139,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 +2411,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 +2569,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 +2597,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 +2644,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 +2664,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 +2682,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 ;drivers/gpu/drm/bridge/analogix/anx7625.h +4
-1@@ -231,6 +231,9 @@#define AP_AUX_ADDR_15_8 0x12#define AP_AUX_ADDR_19_16 0x13 +#define AP_AUX_READ 0x1 +#define AP_AUX_WRITE 0x4 +/* Bit[0:3] AUX status, bit 4 op_en, bit 5 address only */ #define AP_AUX_CTRL_STATUS 0x14#define AP_AUX_CTRL_OP_EN 0x10@@ -474,6 +477,7 @@ struct anx7625_data {u8 bridge_attached;struct drm_connector *connector;struct mipi_dsi_device *dsi; + struct drm_dp_aux aux; };#endif /* __ANX7625_H__ */ --2.34.1.575.g55b058a8bb-goog
PATCH 3/3 dt-bindings: drm/bridge: anx7625: Add aux-bus node
In reply to Hsin-Yi WangList panel under aux-bus node if it's connected to anx7625's aux bus.
--- .../display/bridge/analogix,anx7625.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml +17 -0
@@ -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>; + }; + }; + }; + }; }; };
Signature · 1 line
2.34.1.575.g55b058a8bb-goog
Re: [PATCH 3/3] dt-bindings: drm/bridge: anx7625: Add aux-bus node
Hi Hsin-Yi, thanks for the patch! It's OK for me!
Thanks,
Xin
Quoted 43 lines · Hsin-Yi Wang
List panel under aux-bus node if it's connected to anx7625's aux bus.
Signed-off-by Hsin-Yi Wang <[email protected]>--- .../display/bridge/analogix,anx7625.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml +17
-0@@ -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>; + }; + }; + }; + }; }; };Signature · 1 line
2.34.1.575.g55b058a8bb-goog
Hi Hsin-Yi, thanks for the patch!
Thanks,
Xin
Quoted 51 lines · Hsin-Yi Wang
Use
devm_kzallocinstead of kzalloc and dropkfree(). Let the memory handled by driver detach.Signed-off-by Hsin-Yi Wang <[email protected]>--- drivers/gpu/drm/bridge/analogix/anx7625.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)drivers/gpu/drm/bridge/analogix/anx7625.c +3
-6@@ -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; }Signature · 1 line
2.34.1.575.g55b058a8bb-goog