Hi Kieran, On Fri, Apr 12, 2019 at 04:57:45PM +0100, Kieran Bingham wrote: > Hi Jacopo, > > On 12/04/2019 15:45, Jacopo Mondi wrote: > > Hi Kieran, > > > > On Fri, Apr 12, 2019 at 03:15:46PM +0100, Kieran Bingham wrote: > >> Hi Jacopo, > >> > >> On 16/03/2019 15:47, Jacopo Mondi wrote: > >>> Post-pone the write of the ADV748X_IO_10 register that controls the active > >>> routing between the CP and AFE cores to the 4-lanes CSI-2 TXA at TX > >>> power-up time. > >> > >> "by caching its configuration in the driver state." > >> > >>> > >>> While at there, use the 'csi4_in_sel' name, which matches the register > >> > >> 'While at it, use the...' > >> > >> Except I'm not sure csi4_in_sel is the right name for the cached values > >> as below... > >> > >> > >>> field description in the manual, in place of 'io_10' which is the full > >>> register name. > >>> > >> > >> This has a fixes tag, but doesn't state what the actual problem is? > >> > > > > As reported in the cover letter, please see: > > "[PATCH] media: adv748x: Don't disable CSI-2 on link_setup" > > Ah I see, I had missed that. > > The patch itself should still describe the problem if it's fixing > something. The cover letter will not be available in the git-log. > You're right, I'll expand the commit message. > Ok, so this patch supersedes "[PATCH] media: adv748x: Don't disable > CSI-2 on link_setup" ? > Yes > >> Can I assume that the problem is that the configuration here is being > >> written to the hardware before it is powered up or such? > >> > >> Or perhaps reading through the patch again, is it that the call to > >> link_setup can affect running streams? > > > > The issue I was trying to solve, even with the first patch is that > > going through a link disable (eg. at media graph reset time) wrote to > > the csi4_in_sel register a 0 value, when both TXA and TXB routing > > where disabled and this causes issues on some HDMI transmiters, for > > reason Ian and Hans tried to expand but about which I'm not yet sure > > about. > > Ok, I found that patch and read their comments. So disabling the CSI2 > might trigger a hot-plug event to the transmitter which makes them think > they have been (physically) disconnected in some way, or triggers them > to re-read the EDID which will fail. But we don't really know what the > fault is yet. > Correct. Please note that I've seen this happening with one HDMI transmitter (a chromecast device), while if HDMI source is a laptop everything's fine... > > > The idea here is to cache the routing settings at link_setup time > > (upon activation or deactivation of a link) and apply them to hardware > > at tx power up time, which happens at s_stream(1). > > > > In this way, if streaming is started, we know at least one link is > > enabled and we can write to csi4_in_sel. > > Overall this seems reasonable, only making a change to io10 when either > of the stream states are changed. > Thanks, I'll re-send (maybe even out of this series if it gets stale). Could I have your tag on the next iteration? Thanks j > > >>> Fixes: 9423ca350df7 ("media: adv748x: Implement TX link_setup callback") > >>> Signed-off-by: Jacopo Mondi <jacopo+renesas@xxxxxxxxxx> > >>> --- > >>> drivers/media/i2c/adv748x/adv748x-core.c | 53 ++++++++++++++---------- > >>> drivers/media/i2c/adv748x/adv748x.h | 2 + > >>> 2 files changed, 33 insertions(+), 22 deletions(-) > >>> > >>> diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c > >>> index 0e5a75eb6d75..02135741b1a6 100644 > >>> --- a/drivers/media/i2c/adv748x/adv748x-core.c > >>> +++ b/drivers/media/i2c/adv748x/adv748x-core.c > >>> @@ -305,23 +305,35 @@ static int adv748x_power_down_tx(struct adv748x_csi2 *tx) > >>> > >>> int adv748x_tx_power(struct adv748x_csi2 *tx, bool on) > >>> { > >>> - int val; > >>> + u8 io10_mask = ADV748X_IO_10_CSI1_EN | ADV748X_IO_10_CSI4_EN | > >>> + ADV748X_IO_10_CSI4_IN_SEL_AFE; > >>> + struct adv748x_state *state = tx->state; > >>> + int ret; > >>> > >>> if (!is_tx_enabled(tx)) > >>> return 0; > >>> > >>> - val = tx_read(tx, ADV748X_CSI_FS_AS_LS); > >>> - if (val < 0) > >>> - return val; > >>> + ret = tx_read(tx, ADV748X_CSI_FS_AS_LS); > >>> + if (ret < 0) > >>> + return ret; > >>> > >>> /* > >>> * This test against BIT(6) is not documented by the datasheet, but was > >>> * specified in the downstream driver. > >>> * Track with a WARN_ONCE to determine if it is ever set by HW. > >>> */ > >>> - WARN_ONCE((on && val & ADV748X_CSI_FS_AS_LS_UNKNOWN), > >>> + WARN_ONCE((on && ret & ADV748X_CSI_FS_AS_LS_UNKNOWN), > >>> "Enabling with unknown bit set"); > >>> > >>> + /* Configure TXA routing. */ > >> > >> Should TXA routing be configured even on TXB power up? This function > >> handles both TX code paths. (Edit: possibly yes) > >> > > > > The comment is wrong, thanks for noticing. > > > >> Can the logic that determines state->csi4_in_sel value simply be moved > >> here (or to an independent adv748x_configure_routing() function)? > >> > > > > It has to be changed at link_setup time in rensponse to a media link > > activation or deactivation. > > > >> I think this patch means that changes to routing will now only take > >> effect when starting or stopping a stream, is that right? (If so - could > >> that go into the commit message please?) > >> > > > > Well... > > > > Post-pone the write of the ADV748X_IO_10 register that controls the active > > routing between the CP and AFE cores to the 4-lanes CSI-2 TXA at TX > > power-up time. > > > > Doesn't it say that? Or what confused you is that s_stream->s_power(1) > > and I should mention streaming instead of power up? > > I think of "Power up" meaning at device probe time (or possibly some > runtime-pm event time). But yes, I think the distinction that it now > happens at stream_on/stream_off is important. > > > > > > >> > >> > >> > >>> + if (on) { > >>> + ret = io_clrset(state, ADV748X_IO_10, io10_mask, > >>> + state->csi4_in_sel); > >>> + if (ret) > >>> + return ret; > >>> + } > >>> + > >>> + > >>> return on ? adv748x_power_up_tx(tx) : adv748x_power_down_tx(tx); > >>> } > >>> > >>> @@ -337,10 +349,7 @@ static int adv748x_link_setup(struct media_entity *entity, > >>> struct adv748x_state *state = v4l2_get_subdevdata(sd); > >>> struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd); > >>> bool enable = flags & MEDIA_LNK_FL_ENABLED; > >>> - u8 io10_mask = ADV748X_IO_10_CSI1_EN | > >>> - ADV748X_IO_10_CSI4_EN | > >>> - ADV748X_IO_10_CSI4_IN_SEL_AFE; > >>> - u8 io10 = 0; > >>> + u8 csi4_in_sel = 0; > >>> > >>> /* Refuse to enable multiple links to the same TX at the same time. */ > >>> if (enable && tx->src) > >>> @@ -359,17 +368,19 @@ static int adv748x_link_setup(struct media_entity *entity, > >>> > >>> if (state->afe.tx) { > >>> /* AFE Requires TXA enabled, even when output to TXB */ > >>> - io10 |= ADV748X_IO_10_CSI4_EN; > >>> + csi4_in_sel |= ADV748X_IO_10_CSI4_EN; > >>> if (is_txa(tx)) > >>> - io10 |= ADV748X_IO_10_CSI4_IN_SEL_AFE; > >>> + csi4_in_sel |= ADV748X_IO_10_CSI4_IN_SEL_AFE; > >> > >> Hrm ... this is the one part that I think can't be determined without > >> caching some sort of value to state the routing. > >> > > > > Yes > > But the actual hardware shouldn't be updated if the stream is running > right? (I wonder if the media-controller would prevent that anyway). > > > > > > >>> else > >>> - io10 |= ADV748X_IO_10_CSI1_EN; > >>> + csi4_in_sel |= ADV748X_IO_10_CSI1_EN; > >>> } > >>> > >>> if (state->hdmi.tx) > >>> - io10 |= ADV748X_IO_10_CSI4_EN; > >>> + csi4_in_sel |= ADV748X_IO_10_CSI4_EN; > >>> > >>> - return io_clrset(state, ADV748X_IO_10, io10_mask, io10); > >>> + state->csi4_in_sel = csi4_in_sel; > >>> + > >>> + return 0; > >>> } > >>> > >>> static const struct media_entity_operations adv748x_tx_media_ops = { > >>> @@ -485,7 +496,6 @@ static int adv748x_sw_reset(struct adv748x_state *state) > >>> static int adv748x_reset(struct adv748x_state *state) > >>> { > >>> int ret; > >>> - u8 regval = 0; > >>> > >>> ret = adv748x_sw_reset(state); > >>> if (ret < 0) > >>> @@ -504,6 +514,12 @@ static int adv748x_reset(struct adv748x_state *state) > >>> if (ret) > >>> return ret; > >>> > >> > >> Should adv748x_reset() reset the state->csi4_in_sel cached value to 0 > >> before setting it? > > > > I should better check when reset happens, and if it happens only when > > links have been disabled or not. > > If links are disabled, the variable gets zeroed by the link_setup > > callback. If reset happens with links active, we should not zero it > > otherwise we lose the configuration > > > Ah yes, I missed that the local variable is initialised to zero, and > this state variable is set to the result at the end of the call... > > It does mean that the function ordering will be important here. > > It becomes irrelevant if these conditionals move to the same point > anyway though. > > > > > > >> > >> > >>> + /* Conditionally enable TXa and TXb. */ > >>> + if (is_tx_enabled(&state->txa)) > >>> + state->csi4_in_sel |= ADV748X_IO_10_CSI4_EN; > >>> + if (is_tx_enabled(&state->txb)) > >>> + state->csi4_in_sel |= ADV748X_IO_10_CSI1_EN; > >> > >> This makes it looks like the naming "csi4_in_sel" is less appropriate, > >> as it covers both CSI4 and CSI1... > >> > > > > Blame the hw designers :) > > Always. ... of course they keep blaming us back :D > > > > >> Also, this is confusing two terms, between the 'enable' and the 'select' > >> > >> The _EN bits looks like they control the activation of the CSI > >> transmitter, where as the 'select' bits control the routing. > >> > > > > You are righ. csi4_in_sel should only control the 3 bits used for > > routing, while enabling and disabling of the TXes is controlled by > > other bits of the io_10 register. > > I'll look into changing the name back > > > >> As the is_tx_enabled($TX) state is constant, perhaps that bit could be > >> inferred later when the register is written, and doesn't need to be > >> cached here? > > > > I'll consider that, thanks > > I think it's only the routing choice that needs to be stored in the > state. That would minimise being stored 'globally', and the values could > be determined at the time of programming the register. > > > > > Thanks > > j > > > >> > >> > >>> + > >>> /* Reset TXA and TXB */ > >>> adv748x_tx_power(&state->txa, 1); > >>> adv748x_tx_power(&state->txa, 0); > >>> @@ -513,13 +529,6 @@ static int adv748x_reset(struct adv748x_state *state) > >>> /* Disable chip powerdown & Enable HDMI Rx block */ > >>> io_write(state, ADV748X_IO_PD, ADV748X_IO_PD_RX_EN); > >>> > >>> - /* Conditionally enable TXa and TXb. */ > >>> - if (is_tx_enabled(&state->txa)) > >>> - regval |= ADV748X_IO_10_CSI4_EN; > >>> - if (is_tx_enabled(&state->txb)) > >>> - regval |= ADV748X_IO_10_CSI1_EN; > >>> - io_write(state, ADV748X_IO_10, regval); > >>> - > >>> /* Use vid_std and v_freq as freerun resolution for CP */ > >>> cp_clrset(state, ADV748X_CP_CLMP_POS, ADV748X_CP_CLMP_POS_DIS_AUTO, > >>> ADV748X_CP_CLMP_POS_DIS_AUTO); > >>> diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h > >>> index 4a5a6445604f..27c116d09284 100644 > >>> --- a/drivers/media/i2c/adv748x/adv748x.h > >>> +++ b/drivers/media/i2c/adv748x/adv748x.h > >>> @@ -196,6 +196,8 @@ struct adv748x_state { > >>> struct adv748x_afe afe; > >>> struct adv748x_csi2 txa; > >>> struct adv748x_csi2 txb; > >>> + > >>> + unsigned int csi4_in_sel; > >>> }; > >>> > >>> #define adv748x_hdmi_to_state(h) container_of(h, struct adv748x_state, hdmi) > >>> -- > >>> 2.21.0 > >>> > > -- > Regards > -- > Kieran
Attachment:
signature.asc
Description: PGP signature