[PATCH v7 1/6] drm/tidss: Remove Video Port to Output Port coupling
Tomi Valkeinen
tomi.valkeinen at ideasonboard.com
Mon Feb 6 13:05:53 UTC 2023
On 05/02/2023 15:08, Aradhya Bhatia wrote:
> Hi Tomi,
>
> Thanks for the review!
>
> On 03-Feb-23 16:53, Tomi Valkeinen wrote:
>> On 25/01/2023 13:35, Aradhya Bhatia wrote:
>>> Make DSS Video Ports agnostic of output bus types.
>>>
>>> DSS controllers have had a 1-to-1 coupling between its VPs and its
>>> output ports. This no longer stands true for the new AM625 DSS. This
>>> coupling, hence, has been removed by renaming the 'vp_bus_type' to
>>> 'output_port_bus_type' because the VPs are essentially agnostic of the
>>> bus type and it is the output ports which have a bus type.
>>>
>>> The AM625 DSS has 2 VPs but requires 3 output ports to support its
>>> Dual-Link OLDI video output coming from a single VP.
>>
>> Not a biggie, but this sentence is a bit odd here at the end. Shouldn't
>> it be after the "...stands true for the new AM625 DSS."?
>
> Yes! It should be. Will make the edit.
>
>>
>>> Signed-off-by: Aradhya Bhatia <a-bhatia1 at ti.com>
>>> ---
>>> drivers/gpu/drm/tidss/tidss_dispc.c | 47 +++++++++++++++++------------
>>> drivers/gpu/drm/tidss/tidss_dispc.h | 21 +++++++------
>>> drivers/gpu/drm/tidss/tidss_drv.h | 5 +--
>>> drivers/gpu/drm/tidss/tidss_irq.h | 2 +-
>>> drivers/gpu/drm/tidss/tidss_kms.c | 12 ++++----
>>> 5 files changed, 48 insertions(+), 39 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c
>>> index 165365b515e1..c1c4faccbddc 100644
>>> --- a/drivers/gpu/drm/tidss/tidss_dispc.c
>>> +++ b/drivers/gpu/drm/tidss/tidss_dispc.c
>>> @@ -61,7 +61,7 @@ const struct dispc_features dispc_k2g_feats = {
>>> .min_pclk_khz = 4375,
>>> .max_pclk_khz = {
>>> - [DISPC_VP_DPI] = 150000,
>>> + [DISPC_PORT_DPI] = 150000,
>>> },
>>> /*
>>> @@ -96,7 +96,6 @@ const struct dispc_features dispc_k2g_feats = {
>>> .vp_name = { "vp1" },
>>> .ovr_name = { "ovr1" },
>>> .vpclk_name = { "vp1" },
>>> - .vp_bus_type = { DISPC_VP_DPI },
>>> .vp_feat = { .color = {
>>> .has_ctm = true,
>>> @@ -109,6 +108,9 @@ const struct dispc_features dispc_k2g_feats = {
>>> .vid_name = { "vid1" },
>>> .vid_lite = { false },
>>> .vid_order = { 0 },
>>> +
>>> + .num_output_ports = 1,
>>> + .output_port_bus_type = { DISPC_PORT_DPI },
>>> };
>>
>> Just thinking out loud, as these will get more complex in the future,
>> maybe we should finally group them with struct. E.g. we could define
>> struct array for vps, like (just hacky example):
>>
>> struct {
>> const char *name;
>> const char *clkname;
>> struct tidss_vp_feat feat;
>> } vps[TIDSS_MAX_PORTS];
>>
>> and then use them as:
>>
>> .vps = {
>> {
>> .name = "kala",
>> .clkname = "kissa",
>> .feat.color.has_ctm = true,
>> }, {
>> .name = "kala2",
>> .clkname = "kissa2",
>> .feat.color.has_ctm = false,
>> },
>> },
>>
>> Perhaps something to try in the future.
>>
>
> Yes, agreed! Having that structure will tidy this up.
> I will keep this under future work.
>
>>> static const u16 tidss_am65x_common_regs[DISPC_COMMON_REG_TABLE_LEN] = {
>>> @@ -140,8 +142,8 @@ static const u16 tidss_am65x_common_regs[DISPC_COMMON_REG_TABLE_LEN] = {
>>> const struct dispc_features dispc_am65x_feats = {
>>> .max_pclk_khz = {
>>> - [DISPC_VP_DPI] = 165000,
>>> - [DISPC_VP_OLDI] = 165000,
>>> + [DISPC_PORT_DPI] = 165000,
>>> + [DISPC_PORT_OLDI] = 165000,
>>> },
>>> .scaling = {
>>> @@ -171,7 +173,6 @@ const struct dispc_features dispc_am65x_feats = {
>>> .vp_name = { "vp1", "vp2" },
>>> .ovr_name = { "ovr1", "ovr2" },
>>> .vpclk_name = { "vp1", "vp2" },
>>> - .vp_bus_type = { DISPC_VP_OLDI, DISPC_VP_DPI },
>>> .vp_feat = { .color = {
>>> .has_ctm = true,
>>> @@ -185,6 +186,9 @@ const struct dispc_features dispc_am65x_feats = {
>>> .vid_name = { "vid", "vidl1" },
>>> .vid_lite = { false, true, },
>>> .vid_order = { 1, 0 },
>>> +
>>> + .num_output_ports = 2,
>>> + .output_port_bus_type = { DISPC_PORT_OLDI, DISPC_PORT_DPI },
>>> };
>>> static const u16 tidss_j721e_common_regs[DISPC_COMMON_REG_TABLE_LEN] = {
>>> @@ -229,8 +233,8 @@ static const u16 tidss_j721e_common_regs[DISPC_COMMON_REG_TABLE_LEN] = {
>>> const struct dispc_features dispc_j721e_feats = {
>>> .max_pclk_khz = {
>>> - [DISPC_VP_DPI] = 170000,
>>> - [DISPC_VP_INTERNAL] = 600000,
>>> + [DISPC_PORT_DPI] = 170000,
>>> + [DISPC_PORT_INTERNAL] = 600000,
>>> },
>>> .scaling = {
>>> @@ -260,9 +264,7 @@ const struct dispc_features dispc_j721e_feats = {
>>> .vp_name = { "vp1", "vp2", "vp3", "vp4" },
>>> .ovr_name = { "ovr1", "ovr2", "ovr3", "ovr4" },
>>> .vpclk_name = { "vp1", "vp2", "vp3", "vp4" },
>>> - /* Currently hard coded VP routing (see dispc_initial_config()) */
>>> - .vp_bus_type = { DISPC_VP_INTERNAL, DISPC_VP_DPI,
>>> - DISPC_VP_INTERNAL, DISPC_VP_DPI, },
>>> +
>>
>> I think this line feed is extra.
>
> Okay! Will remove that from all SoC feat structs.
>
>>
>>> .vp_feat = { .color = {
>>> .has_ctm = true,
>>> .gamma_size = 1024,
>>> @@ -273,6 +275,11 @@ const struct dispc_features dispc_j721e_feats = {
>>> .vid_name = { "vid1", "vidl1", "vid2", "vidl2" },
>>> .vid_lite = { 0, 1, 0, 1, },
>>> .vid_order = { 1, 3, 0, 2 },
>>> +
>>> + .num_output_ports = 4,
>>> + /* Currently hard coded VP routing (see dispc_initial_config()) */
>>> + .output_port_bus_type = { DISPC_PORT_INTERNAL, DISPC_PORT_DPI,
>>> + DISPC_PORT_INTERNAL, DISPC_PORT_DPI, },
>>
>> Indent doesn't look right (but it might be just because this is a diff).
>
> I may have missed indenting this.
>
>>
>>> };
>>> static const u16 *dispc_common_regmap;
>>> @@ -287,12 +294,12 @@ struct dispc_device {
>>> void __iomem *base_common;
>>> void __iomem *base_vid[TIDSS_MAX_PLANES];
>>> - void __iomem *base_ovr[TIDSS_MAX_PORTS];
>>> - void __iomem *base_vp[TIDSS_MAX_PORTS];
>>> + void __iomem *base_ovr[TIDSS_MAX_VPS];
>>> + void __iomem *base_vp[TIDSS_MAX_VPS];
>>> struct regmap *oldi_io_ctrl;
>>> - struct clk *vp_clk[TIDSS_MAX_PORTS];
>>> + struct clk *vp_clk[TIDSS_MAX_VPS];
>>> const struct dispc_features *feat;
>>> @@ -300,7 +307,7 @@ struct dispc_device {
>>> bool is_enabled;
>>> - struct dss_vp_data vp_data[TIDSS_MAX_PORTS];
>>> + struct dss_vp_data vp_data[TIDSS_MAX_VPS];
>>> u32 *fourccs;
>>> u32 num_fourccs;
>>> @@ -851,7 +858,7 @@ int dispc_vp_bus_check(struct dispc_device *dispc, u32 hw_videoport,
>>> return -EINVAL;
>>> }
>>> - if (dispc->feat->vp_bus_type[hw_videoport] != DISPC_VP_OLDI &&
>>> + if (dispc->feat->output_port_bus_type[hw_videoport] != DISPC_PORT_OLDI &&
>>
>> Hmm, so is the hw_videoport a vp index or an output index? Sounds like
>> the former, so it's not right, even if at the moment they're identical.
>> We need some kind of mapping between those.
>>
>
> It is indeed a vp index. And yes, I can come up with a mapping mechanism.
>
>> If the mapping can be changed (or just defined in the DT), I think we
>> need a variable in struct dispc_device, which tells the output to which
>> a videoport is connected to. Or vice versa, I'm not sure which direction
>> we need more. If the mapping is always the same on all SoC (but I don't
>> think so), we can have it in the feats.
>>
>
> As of now, the mapping is always same. But I would like to make is
> generalized for future. Hence, I am considering to keep the variable in
> struct dispc_device.
>
> My question though would be, how would one be able to find which kind
> of device is the port connected to, if it is connected to a bridge? For
> example, in case of panels, we have a "connector_type" variable in
> drm_panel which tells what kind of sink it is. But there is no such
> thing in drm_bridge.
>
> This is required because what if we can connect an videoport to either
> an LVDS/OLDI bridge or a DPI bridge.
The connector type shouldn't matter.
The DSS has VPs and outputs. The VPs are "generic" and identical to each
other, except in their possible connections to the outputs. The outputs,
at least at the moment, are DPI, LVDS and internal, where internal is
basically just DPI.
Those are the three different cases we are interested in within the dss
driver, right? Does it matter where the DPI or LVDS output goes?
So what I'm saying is that the DSS device tree data should already
define what kind of configuration we need, and there's no need to look
further into the panel/bridge nodes.
> Also, implementing this might mean removal of the part of code which
> confirms that the panel's "connector_type" indeed expects what the VP
> can provide, unless there is a way to find out what the sink is before
> calling the drm_of_find_panel_or_bridge API.
Hmm, well, each DSS output (port in DT) is of a certain type, so we
should be able to validate that the output and the panel's
connector_type match.
> On the direction, the primary requirement of hw_videoport has been in
> the tidss_dispc.c file where the HW registers are getting configured.
> 'hw_videoport' is a frequently passed parameter in function calls. So,
> at a first glance the former option might makes more sense for
> direction, i.e. to have a variable which tells the output to which a
> videoport is connected to.
Makes sense.
> And while, there is also the tidss_kms.c file, which deals with
> initializing encoders and attaching bridges. This is where the
> output_port is required more often. But I am yet to think of a case
> where the above direction could be an issue.
>
>
>> Also, I wonder if output_port is a good name as it has "port" in it
>> (like video port), and it's a bit long-ish. Would just "output" be
>> enough? We could, of course, shorten it to OP, but that looks odd to me =).
>>
>
>>> fmt->is_oldi_fmt) {
>>> dev_dbg(dispc->dev, "%s: %s is not OLDI-port\n",
>>> __func__, dispc->feat->vp_name[hw_videoport]);
>>> @@ -955,7 +962,7 @@ void dispc_vp_prepare(struct dispc_device *dispc, u32 hw_videoport,
>>> if (WARN_ON(!fmt))
>>> return;
>>> - if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI) {
>>> + if (dispc->feat->output_port_bus_type[hw_videoport] == DISPC_PORT_OLDI) {
>>> dispc_oldi_tx_power(dispc, true);
>>> dispc_enable_oldi(dispc, hw_videoport, fmt);
>>> @@ -1014,7 +1021,7 @@ void dispc_vp_enable(struct dispc_device *dispc, u32 hw_videoport,
>>> align = true;
>>> /* always use DE_HIGH for OLDI */
>>> - if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI)
>>> + if (dispc->feat->output_port_bus_type[hw_videoport] == DISPC_PORT_OLDI)
>>> ieo = false;
>>> dispc_vp_write(dispc, hw_videoport, DISPC_VP_POL_FREQ,
>>> @@ -1040,7 +1047,7 @@ void dispc_vp_disable(struct dispc_device *dispc, u32 hw_videoport)
>>> void dispc_vp_unprepare(struct dispc_device *dispc, u32 hw_videoport)
>>> {
>>> - if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI) {
>>> + if (dispc->feat->output_port_bus_type[hw_videoport] == DISPC_PORT_OLDI) {
>>> dispc_vp_write(dispc, hw_videoport, DISPC_VP_DSS_OLDI_CFG, 0);
>>> dispc_oldi_tx_power(dispc, false);
>>> @@ -1116,10 +1123,10 @@ enum drm_mode_status dispc_vp_mode_valid(struct dispc_device *dispc,
>>> const struct drm_display_mode *mode)
>>> {
>>> u32 hsw, hfp, hbp, vsw, vfp, vbp;
>>> - enum dispc_vp_bus_type bus_type;
>>> + enum dispc_port_bus_type bus_type;
>>> int max_pclk;
>>> - bus_type = dispc->feat->vp_bus_type[hw_videoport];
>>> + bus_type = dispc->feat->output_port_bus_type[hw_videoport];
>>> max_pclk = dispc->feat->max_pclk_khz[bus_type];
>>> diff --git a/drivers/gpu/drm/tidss/tidss_dispc.h b/drivers/gpu/drm/tidss/tidss_dispc.h
>>> index e49432f0abf5..30fb44158347 100644
>>> --- a/drivers/gpu/drm/tidss/tidss_dispc.h
>>> +++ b/drivers/gpu/drm/tidss/tidss_dispc.h
>>> @@ -50,11 +50,11 @@ struct dispc_errata {
>>> bool i2000; /* DSS Does Not Support YUV Pixel Data Formats */
>>> };
>>> -enum dispc_vp_bus_type {
>>> - DISPC_VP_DPI, /* DPI output */
>>> - DISPC_VP_OLDI, /* OLDI (LVDS) output */
>>> - DISPC_VP_INTERNAL, /* SoC internal routing */
>>> - DISPC_VP_MAX_BUS_TYPE,
>>> +enum dispc_port_bus_type {
>>> + DISPC_PORT_DPI, /* DPI output */
>>> + DISPC_PORT_OLDI, /* OLDI (LVDS) output */
>>> + DISPC_PORT_INTERNAL, /* SoC internal routing */
>>> + DISPC_PORT_MAX_BUS_TYPE,
>>
>> Okay, so here you have just "port", not "output_port". In the DT,
>> they're ports, so... Maybe we could use that name too, and for video
>> port always use "vp". The current "hw_videoport" could be easily
>> mistaken with "port".
>
> I see what you are saying and how somebody could confusre hw_videoport
> for a physical connection (i.e. port). I have always understoof
> hw_videoport to be a thing of the actual VP inside the SoC, but that may
> be because I have been working on this, and not just trying to
> understand the code from a high level.
>
> How about if I change the output_port to "out_port"? I am okay to keep
> "output" as the name to. I am saying this becuase I think, only keeping
> "port" might just confuse more, as you mentioned above.
Yes, I agree "port" is not good. Other than that, no strong opinions.
Whatever name you pick, someone will find it confusing ;). Just keep it
consistent, so that all enums, parameters, etc. use it a consistent
manner. If I had to choose, I'd go with the "output", but I'm fine with
other names too.
> And then we can change "hw_videoport" to "vp_index", perhaps, or even
> keep that as it is? Becuase if we do have a VP structure in future
> like you suggested above, "vps" and "vp" would become a close overlap.
> For eg, "vps[vp]".
That is true. I think that was the reason I chose hw_videoport instead
of videoport or vp, although vps[hw_videoport] is only barely better.
vp_index is ok for me, or maybe vp_idx or vp_num to have it a bit shorter.
Tomi
More information about the dri-devel
mailing list