[V3, 2/2] drm/bridge: ti-sn65dsi83: Add TI SN65DSI83 and SN65DSI84 driver
Marek Vasut
marex at denx.de
Tue May 25 13:00:08 UTC 2021
On 5/25/21 2:08 PM, Mike Looijmans wrote:
> See below...
You can just comment inline and skip this top-post.
> Met vriendelijke groet / kind regards,
>
> Mike Looijmans
> System Expert
>
>
> TOPIC Embedded Products B.V.
> Materiaalweg 4, 5681 RJ Best
> The Netherlands
>
> T: +31 (0) 499 33 69 69
> E: mike.looijmans at topicproducts.com
> W: www.topic.nl
>
> Please consider the environment before printing this e-mail
> On 25-05-2021 12:53, Marek Vasut wrote:
>> On 5/17/21 3:23 PM, Mike Looijmans wrote:
>>
>> Which system/soc are you testing this on ?
>
> On a raspberry-pi 4 at the moment.
Ah, OK, it seems this bridge is popular on RPi.
Is there some adapter board with such a bridge for RPi available ?
>> [...]
>>
>>>> +static void sn65dsi83_pre_enable(struct drm_bridge *bridge)
>>>> +{
>>>> + struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge);
>>>> +
>>>> + /*
>>>> + * Reset the chip, pull EN line low for t_reset=10ms,
>>>> + * then high for t_en=1ms.
>>>> + */
>>>> + regcache_mark_dirty(ctx->regmap);
>>>> + gpiod_set_value(ctx->enable_gpio, 0);
>>>> + usleep_range(10000, 11000);
>>>> + gpiod_set_value(ctx->enable_gpio, 1);
>>>> + usleep_range(1000, 1100);
>>> Taking the chip out of reset here is not needed and may even disrupt
>>> things, as the DSI hasn't set up anything yet so the clock may not be
>>> running. I'd move this all into enable and get rid of the pre_enable
>>> call. Similar for post_disable.
>>
>> I am still waiting for someone to confirm the behavior of the DSI
>> clock and data lanes in pre_enable/enable() . The datasheet says the
>> HS clock have to be running and data lanes must be in LP state during
>> init, but I don't think that is guaranteed currently in either
>> pre_enable or enable.
>
> Neither is suited. pre-enable may have nothing, while enable has the
> data lanes sending video according to the docs. So on many systems
> either this driver or the DSI driver will need changes to make it work
> properly.
>
> On the raspberrypi, the DSI has the clock running in pre-enable, hence
> putting everything in pre-enable instead of in enable makes the chip work.
I think someone from the RPi foundation mentioned this before.
> Alternatively, one can modify the RPi DSI code to start sending data
> after the enable calls. That also works on my setup, with everything in
> enable.
>
> The major point here is that you should pick one and only one callback:
> pre-enable or enable. The GPIO reset code as well as writing the
> registers should be done in that one method.
Why , please elaborate ? It seems to be if there was no need for those
two callbacks, there would be no two callbacks in the API in the first
place. There is a chance you will get disable()->enable() sequence
without going through post_disable()->pre_enable() as far as I can tell.
> Same for (post)disable for symmetry. There's no point keeping the chip
> awake after a disable.
>
>
> It's pretty likely for a DSI driver to have the clock active in order to
> allow the panel driver to send MIPI commands and things like that. So
> everything in pre_enable makes sense.
That's how the RPi behaves, on MX8M the DSI clock are active only in
enable. But that might be wrong, see below.
> I don't know how the platform you're testing on is behaving in this
> respect?
iMX8M{M,N}.
And I suspect the DSI behaves differently than on RPi. And that is why I
would like to get some clarification on what (clock, data, LP and HS) is
enabled where from the maintainers.
>> [...]
>>
>>>> +static void sn65dsi83_enable(struct drm_bridge *bridge)
>>>> +{
>>>> + struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge);
>>>> + unsigned int pval;
>>>> + u16 val;
>>>> + int ret;
>>>> +
>>>> + /* Clear reset, disable PLL */
>>>> + regmap_write(ctx->regmap, REG_RC_RESET, 0x00);
>>> Writing 0 to the RESET register is a no-op. Has no effect whatsoever,
>>> just wasting time and code.
>>
>> I would rather keep it to make sure the register is initialized.
>
> Why? It's marked "volatile" so the regmap cache will not touch it. On
> the I2C level, there's absolutely no reason to do this.
It still does trigger a write into the hardware.
>>>> + regmap_write(ctx->regmap, REG_RC_PLL_EN, 0x00);
>>>> +
>>>> + /* Reference clock derived from DSI link clock. */
>>>> + regmap_write(ctx->regmap, REG_RC_LVDS_PLL,
>>>> + REG_RC_LVDS_PLL_LVDS_CLK_RANGE(sn65dsi83_get_lvds_range(ctx)) |
>>>> + REG_RC_LVDS_PLL_HS_CLK_SRC_DPHY);
>>>> + regmap_write(ctx->regmap, REG_DSI_CLK,
>>>> + REG_DSI_CLK_CHA_DSI_CLK_RANGE(sn65dsi83_get_dsi_range(ctx)));
>>>> + regmap_write(ctx->regmap, REG_RC_DSI_CLK,
>>>> + REG_RC_DSI_CLK_DSI_CLK_DIVIDER(sn65dsi83_get_dsi_div(ctx)));
>>>> +
>>>> + /* Set number of DSI lanes and LVDS link config. */
>>>> + regmap_write(ctx->regmap, REG_DSI_LANE,
>>>> + REG_DSI_LANE_LVDS_LINK_CFG_DUAL |
>>>> + REG_DSI_LANE_CHA_DSI_LANES(~(ctx->dsi_lanes - 1)) |
>>>> + /* CHB is DSI85-only, set to default on DSI83/DSI84 */
>>>> + REG_DSI_LANE_CHB_DSI_LANES(3));
>>>> + /* No equalization. */
>>>> + regmap_write(ctx->regmap, REG_DSI_EQ, 0x00);
>>>> +
>>>> + /* RGB888 is the only format supported so far. */
>>>> + val = (ctx->mode.flags & DRM_MODE_FLAG_NHSYNC ?
>>>> + REG_LVDS_FMT_HS_NEG_POLARITY : 0) |
>>>> + (ctx->mode.flags & DRM_MODE_FLAG_NVSYNC ?
>>>> + REG_LVDS_FMT_VS_NEG_POLARITY : 0) |
>>>> + REG_LVDS_FMT_CHA_24BPP_MODE;
>>>> + if (ctx->lvds_dual_link)
>>>> + val |= REG_LVDS_FMT_CHB_24BPP_MODE;
>>>> + else
>>>> + val |= REG_LVDS_FMT_LVDS_LINK_CFG;
>>>> +
>>>> + regmap_write(ctx->regmap, REG_LVDS_FMT, val);
>>>> + regmap_write(ctx->regmap, REG_LVDS_VCOM, 0x05);
>>>> + regmap_write(ctx->regmap, REG_LVDS_LANE,
>>>> + (ctx->lvds_dual_link_even_odd_swap ?
>>>> + REG_LVDS_LANE_EVEN_ODD_SWAP : 0) |
>>>> + REG_LVDS_LANE_CHA_LVDS_TERM|
>>>> + REG_LVDS_LANE_CHB_LVDS_TERM);
>>>> + regmap_write(ctx->regmap, REG_LVDS_CM, 0x00);
>>>> +
>>>> + regmap_bulk_write(ctx->regmap, REG_VID_CHA_ACTIVE_LINE_LENGTH_LOW,
>>>> + &ctx->mode.hdisplay, 2);
>>>
>>> I think this ignores the endian format of the data. So this would
>>> only work on little-endian systems, right?
>>
>> Likely, can you double-check that ?
>> Some cpu_to_le16() could help here then.
>
> I'd add a small helper function that does the endian conversion and
> register write, e.g.
>
> static int sn65dsi83_write16bit(struct sn65dsi83 *ctx, unsigned int reg,
> u16 value)
That just adds unnecessary indirection and makes the code harder to
read, so I won't do that. val = cpu_to_le16(...) looks good enough and
there are already such sequences, i.e. val = ... ; regmap_bulk_write(...);
More information about the dri-devel
mailing list