[Freedreno] [PATCH v5 2/4] drm: introduce drm_writeback_connector_init_with_encoder() API
Abhinav Kumar
quic_abhinavk at quicinc.com
Thu Mar 24 16:36:50 UTC 2022
Hi Liviu
Thanks for the response.
On 3/24/2022 3:12 AM, Liviu Dudau wrote:
> On Wed, Mar 23, 2022 at 11:28:56AM -0700, Abhinav Kumar wrote:
>> Hi Liviu
>
> Hello,
>
>>
>> Thanks for the review.
>>
>> On 3/23/2022 9:46 AM, Liviu Dudau wrote:
>>> On Mon, Mar 21, 2022 at 04:56:43PM -0700, Abhinav Kumar wrote:
>>>> For vendors drivers which pass an already allocated and
>>>> initialized encoder especially for cases where the encoder
>>>> hardware is shared OR the writeback encoder shares the resources
>>>> with the rest of the display pipeline introduce a new API,
>>>> drm_writeback_connector_init_with_encoder() which expects
>>>> an initialized encoder as a parameter and only sets up the
>>>> writeback connector.
>>>>
>>>> changes in v5:
>>>> - reorder this change to come before in the series
>>>> to avoid incorrect functionality in subsequent changes
>>>> - continue using struct drm_encoder instead of
>>>> struct drm_encoder * and switch it in next change
>>>>
>>>> Signed-off-by: Abhinav Kumar <quic_abhinavk at quicinc.com>
>>>
>>> Hi Abhinav,
>>>
>>>> ---
>>>> drivers/gpu/drm/drm_writeback.c | 143 ++++++++++++++++++++++++++++------------
>>>> include/drm/drm_writeback.h | 5 ++
>>>> 2 files changed, 106 insertions(+), 42 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/drm_writeback.c b/drivers/gpu/drm/drm_writeback.c
>>>> index dc2ef12..abe78b9 100644
>>>> --- a/drivers/gpu/drm/drm_writeback.c
>>>> +++ b/drivers/gpu/drm/drm_writeback.c
>>>> @@ -149,37 +149,15 @@ static const struct drm_encoder_funcs drm_writeback_encoder_funcs = {
>>>> .destroy = drm_encoder_cleanup,
>>>> };
>>>> -/**
>>>> - * drm_writeback_connector_init - Initialize a writeback connector and its properties
>>>> - * @dev: DRM device
>>>> - * @wb_connector: Writeback connector to initialize
>>>> - * @con_funcs: Connector funcs vtable
>>>> - * @enc_helper_funcs: Encoder helper funcs vtable to be used by the internal encoder
>>>> - * @formats: Array of supported pixel formats for the writeback engine
>>>> - * @n_formats: Length of the formats array
>>>> - * @possible_crtcs: possible crtcs for the internal writeback encoder
>>>> - *
>>>> - * This function creates the writeback-connector-specific properties if they
>>>> - * have not been already created, initializes the connector as
>>>> - * type DRM_MODE_CONNECTOR_WRITEBACK, and correctly initializes the property
>>>> - * values. It will also create an internal encoder associated with the
>>>> - * drm_writeback_connector and set it to use the @enc_helper_funcs vtable for
>>>> - * the encoder helper.
>>>> - *
>>>> - * Drivers should always use this function instead of drm_connector_init() to
>>>> - * set up writeback connectors.
>>>> - *
>>>> - * Returns: 0 on success, or a negative error code
>>>> - */
>>>> -int drm_writeback_connector_init(struct drm_device *dev,
>>>> - struct drm_writeback_connector *wb_connector,
>>>> - const struct drm_connector_funcs *con_funcs,
>>>> - const struct drm_encoder_helper_funcs *enc_helper_funcs,
>>>> - const u32 *formats, int n_formats, uint32_t possible_crtcs)
>>>> +static int drm_writeback_connector_setup(struct drm_device *dev,
>>>> + struct drm_writeback_connector *wb_connector,
>>>> + const struct drm_connector_funcs *con_funcs, const u32 *formats,
>>>> + int n_formats)
>>>> {
>>>> struct drm_property_blob *blob;
>>>> - struct drm_connector *connector = &wb_connector->base;
>>>> struct drm_mode_config *config = &dev->mode_config;
>>>> + struct drm_connector *connector = &wb_connector->base;
>>>> +
>>>
>>> Point of this reordering the statements is...?
>> This diff can be avoided. There was no reason to reorder this. I will remove
>> this re-order.
>>>
>>>> int ret = create_writeback_properties(dev);
>>>> if (ret != 0)
>>>> @@ -187,18 +165,10 @@ int drm_writeback_connector_init(struct drm_device *dev,
>>>> blob = drm_property_create_blob(dev, n_formats * sizeof(*formats),
>>>> formats);
>>>> - if (IS_ERR(blob))
>>>> - return PTR_ERR(blob);
>>>> -
>>>> - drm_encoder_helper_add(&wb_connector->encoder, enc_helper_funcs);
>>>> -
>>>> - wb_connector->encoder.possible_crtcs = possible_crtcs;
>>>> -
>>>> - ret = drm_encoder_init(dev, &wb_connector->encoder,
>>>> - &drm_writeback_encoder_funcs,
>>>> - DRM_MODE_ENCODER_VIRTUAL, NULL);
>>>> - if (ret)
>>>> - goto fail;
>>>> + if (IS_ERR(blob)) {
>>>> + ret = PTR_ERR(blob);
>>>> + return ret;
>>>> + }
>>>
>>> I don't see why you have changed the earlier code to store the result of PTR_ERR into
>>> ret other than to help your debugging. I suggest that you keep the existing code that
>>> returns PTR_ERR(blob) directly and you will have a nicer diff stat as well.
>> Sure, i can fix this for a smaller diff stat.
>>>
>>>> connector->interlace_allowed = 0;
>>>> @@ -237,13 +207,102 @@ int drm_writeback_connector_init(struct drm_device *dev,
>>>> attach_fail:
>>>> drm_connector_cleanup(connector);
>>>> connector_fail:
>>>> - drm_encoder_cleanup(&wb_connector->encoder);
>>>> -fail:
>>>> drm_property_blob_put(blob);
>>>> return ret;
>>>> }
>>>> +
>>>> +/**
>>>> + * drm_writeback_connector_init - Initialize a writeback connector and its properties
>>>> + * @dev: DRM device
>>>> + * @wb_connector: Writeback connector to initialize
>>>> + * @con_funcs: Connector funcs vtable
>>>> + * @enc_helper_funcs: Encoder helper funcs vtable to be used by the internal encoder
>>>> + * @formats: Array of supported pixel formats for the writeback engine
>>>> + * @n_formats: Length of the formats array
>>>> + * @possible_crtcs: possible crtcs for the internal writeback encoder
>>>> + *
>>>> + * This function creates the writeback-connector-specific properties if they
>>>> + * have not been already created, initializes the connector as
>>>> + * type DRM_MODE_CONNECTOR_WRITEBACK, and correctly initializes the property
>>>> + * values. It will also create an internal encoder associated with the
>>>> + * drm_writeback_connector and set it to use the @enc_helper_funcs vtable for
>>>> + * the encoder helper.
>>>> + *
>>>> + * Drivers should always use this function instead of drm_connector_init() to
>>>> + * set up writeback connectors.
>>>> + *
>>>> + * Returns: 0 on success, or a negative error code
>>>> + */
>>>> +int drm_writeback_connector_init(struct drm_device *dev,
>>>> + struct drm_writeback_connector *wb_connector,
>>>> + const struct drm_connector_funcs *con_funcs,
>>>> + const struct drm_encoder_helper_funcs *enc_helper_funcs,
>>>> + const u32 *formats, int n_formats, uint32_t possible_crtcs)
>>>> +{
>>>> + int ret = 0;
>>>> +
>>>> + drm_encoder_helper_add(&wb_connector->encoder, enc_helper_funcs);
>>>> +
>>>> + wb_connector->encoder.possible_crtcs = possible_crtcs;
>>>> +
>>>> + ret = drm_encoder_init(dev, &wb_connector->encoder,
>>>> + &drm_writeback_encoder_funcs,
>>>> + DRM_MODE_ENCODER_VIRTUAL, NULL);
>>>> + if (ret)
>>>> + return ret;
>>>> +
>>>> + ret = drm_writeback_connector_setup(dev, wb_connector, con_funcs, formats,
>>>> + n_formats);
>>>> +
>>>> + if (ret)
>>>> + drm_encoder_cleanup(&wb_connector->encoder);
>>>> +
>>>> + return ret;
>>>> +}
>>>> EXPORT_SYMBOL(drm_writeback_connector_init);
>>>> +/**
>>>> + * drm_writeback_connector_init_with_encoder - Initialize a writeback connector and its properties
>>>> + * using the encoder which already assigned and initialized
>>>> + *
>>>> + * @dev: DRM device
>>>> + * @wb_connector: Writeback connector to initialize
>>>> + * @con_funcs: Connector funcs vtable
>>>> + * @enc_helper_funcs: Encoder helper funcs vtable to be used by the internal encoder
>>>> + * @formats: Array of supported pixel formats for the writeback engine
>>>> + * @n_formats: Length of the formats array
>>>> + *
>>>> + * This function creates the writeback-connector-specific properties if they
>>>> + * have not been already created, initializes the connector as
>>>> + * type DRM_MODE_CONNECTOR_WRITEBACK, and correctly initializes the property
>>>> + * values.
>>>> + *
>>>> + * This function assumes that the drm_writebac_connector's encoder has already been
>>>
>>> spelling: writeback
>> Ack. will fix this.
>>>
>>>> + * created and initialized before invoking this function.
>>>> + *
>>>> + * In addition, this function also assumes that callers of this API will manage
>>>> + * assigning the encoder helper functions, possible_crtcs and any other encoder
>>>> + * specific operation which is otherwise handled by drm_writeback_connector_init().
>>>> + *
>>>> + * Drivers should always use this function instead of drm_connector_init() to
>>>> + * set up writeback connectors.
>>>
>>> .... if they want to manage themselves the lifetime of the associated encoder.
>>>
>>> We're not trying to replace drm_writeback_connector_init() function here, only to
>>> provide an alternative function to call for special cases.
>>
>> Yes, we are trying to provide an alternative function call for special case
>> where the encoder is a shared encoder and/or where the resources of the
>> writeback encoder are shared with other hardware blocks.
>>
>> I can add that comment to this function's doc.
>>
>>>
>>>> + *
>>>> + * Returns: 0 on success, or a negative error code
>>>> + */
>>>> +int drm_writeback_connector_init_with_encoder(struct drm_device *dev,
>>>> + struct drm_writeback_connector *wb_connector,
>>>> + const struct drm_connector_funcs *con_funcs, const u32 *formats,
>>>> + int n_formats)
>>>
>>> Where is the encoder parameter? Isn't that the reason why the function is called
>>> `_with_encoder`?
>> The encoder parameter is skipped here because this function assumes that
>> wb_connector->encoder has already been initialized, setup with functions and
>> its possible_crts have already been set prior to calling this function like
>> the vc4 example shows. So this function doesnt need an explicit encoder
>> parameter. Let me know if thats a concern.
>>>
>>> I think there might have been too many version of these patchsets and things are
>>> starting to be confusing. Please revisit the series without rushing and come up with
>>> a plan of action. My understanding of watching this series has been that you're
>>> trying to come up with a function that does *connector* initialisation but skips the
>>> *encoder* initialisation because it might have been already done by the driver. The
>>> idea will be then to have a function `drm_writeback_connector_init_with_encoder()`
>>> that does *all* the work that `drm_writeback_connector_init()` does at the moment minus
>>> the encoder initialisation part. Then `drm_writeback_connector_init()` only
>>> initialises the internal encoder and calls `drm_writeback_connector_init_with_encoder()`.
>>> There is no need to have the `drm_writeback_connector_setup()` function at all.
>>>
>>> Best regards,
>>> Liviu
>>>
>>
>> I agree there have been a 4 revisions prior to this because of the way this
>> affects the existing writeback drivers. So initial revision was a bit
>> intrusive into other drivers (which was just mostly a take over from the
>> previous patchset posted by the Co-developer ) and since rev3 we have
>> decided to have a separate API drm_writeback_connector_init_with_encoder()
>> so that existing clients are unaffected and it works seamlessly under the
>> hood.
>>
>> Only clients which already embed an encoder (vc4) and the new ones which
>> have special encoder requirements like the MSM driver for which I am
>> preparing these changes for will use the new API.
>>
>> Apologies for the revisions, but thanks to some great feedback from you and
>> laurent its shaping up nicely and reaching its conclusion I feel.
>
> I think it is only natural that there will be some iterations. If I remember
> correctly, the initial writeback series has something like 13 revisions :)
>
>>
>> So i think this revision is pretty close to being clean thanks to the
>> feedback you gave on rev4. Between rev4 and this one I didnt drastically
>> change the design other than re-ordering the changes to avoid the
>> intermediate patches having an incorrect state for the vc4 encoder. So all
>> your comments related to the encoder_cleanup() and vc4's encoder not getting
>> initialized would have gotten addressed but overall concept remained same.
>>
>> You are right, we are trying to come up with a function which does connector
>> initialization but skips the encoder part because that has already been done
>> in the client side of this API ( hence _with_encoder() name ). The
>> "_with_encoder" indicates that the caller already has an encoder for the
>> writeback connector which is being passed so there is no need to pass the
>> encoder again.
>>
>> I thought this addresses all the concerns posted in the previous series.
>>
>> So are you suggesting something like below?
>>
>> 1) rename drm_writeback_connector_setup() to
>> drm_writeback_connector_init_with_encoder()
>> (essentially thats what will end up happening )
>
> Correct. Without the pointless reordering of code it should be about 3 lines of code
> that get removed (the calls to drm_encoder_helper_add() and drm_encoder_init()).
>
But isnt thats how it already looks.
int drm_writeback_connector_init(struct drm_device *dev,
struct drm_writeback_connector *wb_connector,
const struct drm_connector_funcs *con_funcs,
const struct drm_encoder_helper_funcs *enc_helper_funcs,
const u32 *formats, int n_formats, uint32_t possible_crtcs)
{
int ret = 0;
wb_connector->encoder = &wb_connector->internal_encoder;
drm_encoder_helper_add(wb_connector->encoder, enc_helper_funcs);
wb_connector->encoder->possible_crtcs = possible_crtcs;
ret = drm_encoder_init(dev, wb_connector->encoder,
&drm_writeback_encoder_funcs,
DRM_MODE_ENCODER_VIRTUAL, NULL);
if (ret)
return ret;
ret = drm_writeback_connector_setup(dev, wb_connector, con_funcs,
formats,
n_formats);
So the only change you are requesting is that, instead of having a new
drm_writeback_connector_setup(), just call
drm_writeback_connector_init_with_encoder().
It will essentially look like
int drm_writeback_connector_init(struct drm_device *dev,
struct drm_writeback_connector *wb_connector,
const struct drm_connector_funcs *con_funcs,
const struct drm_encoder_helper_funcs *enc_helper_funcs,
const u32 *formats, int n_formats, uint32_t possible_crtcs)
{
int ret = 0;
wb_connector->encoder = &wb_connector->internal_encoder;
drm_encoder_helper_add(wb_connector->encoder, enc_helper_funcs);
wb_connector->encoder->possible_crtcs = possible_crtcs;
ret = drm_encoder_init(dev, wb_connector->encoder,
&drm_writeback_encoder_funcs,
DRM_MODE_ENCODER_VIRTUAL, NULL);
if (ret)
return ret;
ret = drm_writeback_connector_init_with_encoder(dev, wb_connector,
con_funcs, formats,
n_formats);
drm_writeback_connector_init_with_encoder() will still not have an
encoder parameter because of what I wrote previously.
Hope this is what you had in mind as well.
>>
>> 2) Inside drm_writeback_connector_init() check:
>>
>> drm_writeback_connector_init(.....)
>> {
>> if (!wb_conn->encoder)
>> initialize the encoder
>
> No, the assumption of drm_writeback_connector_init() is that we will provide the
> encoder, so no need to check that one is already provided. What you could do is:
>
> WARN_ON(wb_conn->encoder);
>
Got it, i will add a warning inside drm_writeback_connector_init() to
emphasize that its only meant for cases where an encoder is not provided.
> before we overwrite the encoder. That way we will get a nice warning in the kernel
> log if someone tries to call drm_writeback_connector_init() with a preset encoder.
>
>>
>> call drm_writeback_**_init_with_encoder()
>> }
>>
>> This will also work but have the foll concerns/questions:
>>
>> 1) Will drm_writeback_connector_init_with_encoder() be exported if we change
>> as per your suggestion or will all clients continue to use
>> drm_writeback_connector_init() only? We wanted to have a separate function
>> for new clients.
>
> Yes, we will need to export drm_writeback_connector_init_with_encoder() as well.
>
Alright, so vc4 and new vendors which provide their own encoder will use
this one. So no changes to the rest of the series.
>>
>> 2) How will we detect that encoder needs to be initialized without it being
>> a pointer which happens in the later change. So ordering becomes an issue.
>
> I think the init problem is simple. You either call drm_writeback_connector_init()
> and the framework provides you with an encoder, or you call
> drm_writeback_connector_init_with_encoder() and the framework will use yours. The
> problems will show up on the cleanup and exit codes, where we need to be able to skip
> the cleanup if the encoder pointer is not the internal one. I think a simple
>
> if (connector->encoder == &connector->internal_encoder)
> do_encoder_cleanup_work_here()
>
> should work.
Sorry, I am missing something here.
Even in this current patch, the drm_encoder_cleanup() is done only
inside drm_writeback_connector_init() where internal_encoder is used.
For drm_writeback_connector_init_with_encoder(), we dont do the cleanup
and expect the caller to do it like vc4 does in the next patch.
So why do we need such a condition?
>
>>
>> Thats why I thought this is the best way to address the comments and keep
>> the functionality intact with each change.
>>
>> Let me know if I have misunderstood some comment or idea.
>
> I hope that with these clarifications we are both on the same page.
>
> Best regards,
> Liviu
>
>
>
>>
>>
>>
>>>
>>>> +{
>>>> + int ret = 0;
>>>> +
>>>> + ret = drm_writeback_connector_setup(dev, wb_connector, con_funcs, formats,
>>>> + n_formats);
>>>> +
>>>> + return ret;
>>>> +}
>>>> +EXPORT_SYMBOL(drm_writeback_connector_init_with_encoder);
>>>> +
>>>> int drm_writeback_set_fb(struct drm_connector_state *conn_state,
>>>> struct drm_framebuffer *fb)
>>>> {
>>>> diff --git a/include/drm/drm_writeback.h b/include/drm/drm_writeback.h
>>>> index db6214f..0093bab 100644
>>>> --- a/include/drm/drm_writeback.h
>>>> +++ b/include/drm/drm_writeback.h
>>>> @@ -152,6 +152,11 @@ int drm_writeback_connector_init(struct drm_device *dev,
>>>> const struct drm_encoder_helper_funcs *enc_helper_funcs,
>>>> const u32 *formats, int n_formats, uint32_t possible_crtcs);
>>>> +int drm_writeback_connector_init_with_encoder(struct drm_device *dev,
>>>> + struct drm_writeback_connector *wb_connector,
>>>> + const struct drm_connector_funcs *con_funcs, const u32 *formats,
>>>> + int n_formats);
>>>> +
>>>> int drm_writeback_set_fb(struct drm_connector_state *conn_state,
>>>> struct drm_framebuffer *fb);
>>>> --
>>>> 2.7.4
>>>>
>>>
>
More information about the Freedreno
mailing list