On Fri, Jan 14, 2022 at 04:48:36AM +0100, Marek Vasut wrote:
> The ICN6211 chip starts in I2C configuration mode after cold boot.
> Implement support for configuring the chip via I2C in addition to
> the current DSI LP command mode configuration support. The later
> seems to be available only on chips which have additional MCU on
> the panel/bridge board which preconfigures the ICN6211, while the
> I2C configuration mode added by this patch does not require any
> such MCU.
> 
> Signed-off-by: Marek Vasut <[email protected]>
> Cc: Jagan Teki <[email protected]>
> Cc: Robert Foss <[email protected]>
> Cc: Sam Ravnborg <[email protected]>
> Cc: Thomas Zimmermann <[email protected]>
> To: [email protected]
> ---
>  drivers/gpu/drm/bridge/chipone-icn6211.c | 219 +++++++++++++++++++----
>  1 file changed, 188 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/gpu/drm/bridge/chipone-icn6211.c 
> b/drivers/gpu/drm/bridge/chipone-icn6211.c
> index 8226fefeedfc9..313c588297eca 100644
> --- a/drivers/gpu/drm/bridge/chipone-icn6211.c
> +++ b/drivers/gpu/drm/bridge/chipone-icn6211.c
> @@ -11,6 +11,7 @@
>  
>  #include <linux/delay.h>
>  #include <linux/gpio/consumer.h>
> +#include <linux/i2c.h>
>  #include <linux/module.h>
>  #include <linux/of_device.h>
>  #include <linux/regulator/consumer.h>
> @@ -133,14 +134,17 @@
>  
>  struct chipone {
>       struct device *dev;
> +     struct i2c_client *client;
>       struct drm_bridge bridge;
>       struct drm_bridge *panel_bridge;
>       struct device_node *host_node;
> +     struct mipi_dsi_device *dsi;
>       struct gpio_desc *enable_gpio;
>       struct regulator *vdd1;
>       struct regulator *vdd2;
>       struct regulator *vdd3;
>       int dsi_lanes;
> +     bool interface_i2c;
>  };
>  
>  static inline struct chipone *bridge_to_chipone(struct drm_bridge *bridge)
> @@ -172,20 +176,14 @@ bridge_to_mode(struct drm_bridge *bridge, struct 
> drm_atomic_state *state)
>       return &crtc_state->adjusted_mode;
>  }
>  
> -static inline int chipone_dsi_write(struct chipone *icn,  const void *seq,
> -                                 size_t len)
> +static void ICN6211_DSI(struct chipone *icn, u8 reg, u8 val)
>  {
> -     struct mipi_dsi_device *dsi = to_mipi_dsi_device(icn->dev);
> -
> -     return mipi_dsi_generic_write(dsi, seq, len);
> +     if (icn->interface_i2c)
> +             i2c_smbus_write_byte_data(icn->client, reg, val);
> +     else
> +             mipi_dsi_generic_write(icn->dsi, (u8[]){reg, val}, 2);
>  }
>  
> -#define ICN6211_DSI(icn, seq...)                             \
> -     {                                                       \
> -             const u8 d[] = { seq };                         \
> -             chipone_dsi_write(icn, d, ARRAY_SIZE(d));       \
> -     }
> -
>  static void chipone_configure_pll(struct chipone *icn,
>                                 const struct drm_display_mode *mode)
>  {
> @@ -282,7 +280,10 @@ static void chipone_atomic_enable(struct drm_bridge 
> *bridge,
>       bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
>       bus_flags = bridge_state->output_bus_cfg.flags;
>  
> -     ICN6211_DSI(icn, MIPI_CFG_PW, MIPI_CFG_PW_CONFIG_DSI);
> +     if (icn->interface_i2c)
> +             ICN6211_DSI(icn, MIPI_CFG_PW, MIPI_CFG_PW_CONFIG_I2C);
> +     else
> +             ICN6211_DSI(icn, MIPI_CFG_PW, MIPI_CFG_PW_CONFIG_DSI);
>  
>       ICN6211_DSI(icn, HACTIVE_LI, mode->hdisplay & 0xff);
>  
> @@ -396,11 +397,86 @@ static void chipone_atomic_post_disable(struct 
> drm_bridge *bridge,
>       gpiod_set_value(icn->enable_gpio, 0);
>  }
>  
> +static int chipone_dsi_attach(struct chipone *icn)
> +{
> +     struct mipi_dsi_device *dsi = icn->dsi;
> +     int ret;
> +
> +     dsi->lanes = icn->dsi_lanes;
> +     dsi->format = MIPI_DSI_FMT_RGB888;
> +     dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
> +                       MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET;
> +
> +     ret = mipi_dsi_attach(dsi);
> +     if (ret < 0)
> +             dev_err(icn->dev, "failed to attach dsi\n");
> +
> +     return ret;
> +}
> +
> +static int chipone_dsi_setup(struct chipone *icn)
> +{
> +     struct device *dev = icn->dev;
> +     struct mipi_dsi_device *dsi;
> +     struct mipi_dsi_host *host;
> +     int ret = 0;
> +
> +     const struct mipi_dsi_device_info info = {
> +             .type = "chipone",
> +             .channel = 0,
> +             .node = NULL,
> +     };
> +
> +     host = of_find_mipi_dsi_host_by_node(icn->host_node);
> +     if (!host) {
> +             dev_err(dev, "failed to find dsi host\n");
> +             return -EPROBE_DEFER;
> +     }
> +
> +     dsi = mipi_dsi_device_register_full(host, &info);
> +     if (IS_ERR(dsi)) {
> +             return dev_err_probe(dev, PTR_ERR(dsi),
> +                                  "failed to create dsi device\n");
> +     }
> +
> +     icn->dsi = dsi;
> +
> +     ret = chipone_dsi_attach(icn);
> +     if (ret < 0)
> +             mipi_dsi_device_unregister(dsi);
> +
> +     return ret;
> +}
> +
>  static int chipone_attach(struct drm_bridge *bridge, enum 
> drm_bridge_attach_flags flags)
>  {
>       struct chipone *icn = bridge_to_chipone(bridge);
> +     struct drm_bridge *abridge = bridge;
> +     int ret;
> +
> +     if (icn->interface_i2c) {
> +             ret = chipone_dsi_setup(icn);
> +             if (ret)
> +                     return ret;
> +
> +             abridge = &icn->bridge;

This needs to happen at probe/bind time. See:
https://www.kernel.org/doc/html/latest/gpu/drm-kms-helpers.html#special-care-with-mipi-dsi-bridges

Maxime

Attachment: signature.asc
Description: PGP signature

Reply via email to