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 > Cc: Jagan Teki > Cc: Robert Foss > Cc: Sam Ravnborg > Cc: Thomas Zimmermann > To: dri-devel@lists.freedesktop.org > --- > 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 > #include > +#include > #include > #include > #include > @@ -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