Message ID | 20231216162639.125215-20-knaerzche@gmail.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel+bounces-2267-ouuuleilei=gmail.com@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7300:24d3:b0:fb:cd0c:d3e with SMTP id r19csp315643dyi; Sat, 16 Dec 2023 08:33:42 -0800 (PST) X-Google-Smtp-Source: AGHT+IHX+QWNZnl66VwkQlzdd8GNXUDZ0JTPvxGVlLOMWjSjgUZTVebO1PbBVRKHKCAYgPXH8Y6L X-Received: by 2002:a05:6102:956:b0:462:9eb3:9bdd with SMTP id a22-20020a056102095600b004629eb39bddmr10132907vsi.28.1702744422302; Sat, 16 Dec 2023 08:33:42 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1702744422; cv=none; d=google.com; s=arc-20160816; b=Ms4VT+JlzCvb+/q63OgbnZt606LaeUUOwe6mJeBNSotxYJDyrG/QPkWQ1z5eoRdUSC qW4MiozyUh95RQ53QuvU4T1T3nNyH1y8PT2NRNa6S0i7YUWLenHawfBb8TjlL7V6a0u7 hiWdcMe3LNC0G4QQPjXquE4rP5PyZswiu5wacla5ZDU9v2ORviPIU/o0cS1gs/RNLqWm uVlV5/2lFPHFdKcJ2qVP9KUu1+mrTnQV/JdZSa8KVm6SGG00wGXqmmqapXFw0f/j3uVI M7V42yTgS3k7cAQjdvaOMc9tb6TmbscG37VwoBDJA8UXM+F2A5QuWCwy5y5XwwgkpmMO UzRQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=xquaKm3YPbbfHci/n27FNskS85Fe2FEHpYLHWs9wnrA=; fh=nzMX5Jolb3GculGR3f1Z1ReHOqdNjcdazDY5R3X+7M0=; b=wVAowbTRIQ5OAQJ1765AkyTXiWnDjuJOqE3KdW411oHT5yxKQcMlKqRsGtmitSnIwy pvmhOgizXdRKPqIL8hZGKlDsENcWnYwWFx/464oUr1tSCDj7M+D3f/9wuLm1m8tIvohk ix/Gl3U6HHagPMiBPYXqQUDOK0dz7G1b3s8c2wW8Y8JJdRUyfSBVfFUg4P6QFV8Lv5SF uxmf1lywXzRKsZ7xg1B+0qt6VU2IhfBjxHYfjVX39gpmoZt2ydMxfQc9+I6I64VcD5MV Lgc1MJX6Fn0SzDqQmPVvFqa9Akj9h3pLZR227/ewe4ROC0RxRnd7bC4jhw6NgFSJRp/r dTKg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b="eunQT72/"; spf=pass (google.com: domain of linux-kernel+bounces-2267-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) smtp.mailfrom="linux-kernel+bounces-2267-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from ny.mirrors.kernel.org (ny.mirrors.kernel.org. [147.75.199.223]) by mx.google.com with ESMTPS id m13-20020a0561023e8d00b004661fd499a7si3432673vsv.96.2023.12.16.08.33.42 for <ouuuleilei@gmail.com> (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 16 Dec 2023 08:33:42 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-2267-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) client-ip=147.75.199.223; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b="eunQT72/"; spf=pass (google.com: domain of linux-kernel+bounces-2267-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) smtp.mailfrom="linux-kernel+bounces-2267-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ny.mirrors.kernel.org (Postfix) with ESMTPS id 1791D1C21957 for <ouuuleilei@gmail.com>; Sat, 16 Dec 2023 16:33:42 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 84F363FB12; Sat, 16 Dec 2023 16:27:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="eunQT72/" X-Original-To: linux-kernel@vger.kernel.org Received: from mail-ed1-f45.google.com (mail-ed1-f45.google.com [209.85.208.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 51058381B2; Sat, 16 Dec 2023 16:27:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-ed1-f45.google.com with SMTP id 4fb4d7f45d1cf-548ce39b101so1996812a12.2; Sat, 16 Dec 2023 08:27:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1702744039; x=1703348839; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=xquaKm3YPbbfHci/n27FNskS85Fe2FEHpYLHWs9wnrA=; b=eunQT72/2oqPu2ddLmo+onfpQsJkJ+S4avC2v9wcjvAYsyllXxZfBaF4qgeojNea+V LQQs34MxoKsRJ2VsEtYuCdDRihDf2Nj0M6AQKlq+XWpspGVStDUI5kzCzzaam5DO5p+/ yttIxUjBd7s1HJ1LbxR8kJPzUuTABJ5O+zadxD7dIsE+R/oNYpFoxjKI+OqnEb/t9BGw hSNFYwDeKTO2wx2O/34DkdKdN4Cdz6eAcsHTjdq9J7Y2nUUHNBijJhx7LQUwpHsYvHQD 0G9u9KHA/LErvBLtehFl0nVdHv6eLDSrAzZueI1Q+jVTFfPgeiYBn7UTQvstuH5D4gjt hMNQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1702744039; x=1703348839; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=xquaKm3YPbbfHci/n27FNskS85Fe2FEHpYLHWs9wnrA=; b=JMqEa71EEABFS1YanCvigLl6W3SFDM64FHkISUmV6bFsUUj8AEGi9cHTWEDsYWgH0i jJpAk02+AS5Qjqms1JPQF6JSBJ9yo1Tf7Q8vj0TmZ+rFlEOpU1Zk7LhZRS10M1WvQn8f Rp52sLWms78+iCmIUQueeuxc10TZz7grcphtVz03vQ69XtyrHBMqT6zBWO79dVAy72jL zPdp+NR0lB9d+UC1zOROYVxyoUK5Yo+0L5itRFycH82wEhF0bo3NGG/p+vD2VMXPIMyT lFU1IxKfNNYcFRq1AgKGon0+EM3i8zL7L19DAX/ohDf3fEi2whkrtxVIK/JJCye7RY1I sOrw== X-Gm-Message-State: AOJu0YwWqiwIgZfbPnmH4yh2kKw8AofO7gzn3DbXV7Pm13T088aknXR3 A2fc9A+w1M9augoE4u8KVw== X-Received: by 2002:a17:906:2c7:b0:a23:2aa7:d48b with SMTP id 7-20020a17090602c700b00a232aa7d48bmr212918ejk.14.1702744039643; Sat, 16 Dec 2023 08:27:19 -0800 (PST) Received: from U4.lan ([2a02:810b:f40:4300:e807:d345:6f47:1db9]) by smtp.gmail.com with ESMTPSA id st10-20020a170907c08a00b00a1cd0794696sm11990362ejc.53.2023.12.16.08.27.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 16 Dec 2023 08:27:19 -0800 (PST) From: Alex Bee <knaerzche@gmail.com> To: Sandy Huang <hjc@rock-chips.com>, =?utf-8?q?Heiko_St=C3=BCbner?= <heiko@sntech.de>, Andy Yan <andyshrk@163.com>, Rob Herring <robh+dt@kernel.org>, Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>, Conor Dooley <conor+dt@kernel.org>, Maarten Lankhorst <maarten.lankhorst@linux.intel.com>, Maxime Ripard <mripard@kernel.org>, Thomas Zimmermann <tzimmermann@suse.de> Cc: David Airlie <airlied@gmail.com>, Daniel Vetter <daniel@ffwll.ch>, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org, linux-kernel@vger.kernel.org, Alex Bee <knaerzche@gmail.com> Subject: [PATCH v2 19/27] drm/rockchip: inno_hdmi: Move tmds rate to connector state subclass Date: Sat, 16 Dec 2023 17:26:30 +0100 Message-ID: <20231216162639.125215-20-knaerzche@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231216162639.125215-1-knaerzche@gmail.com> References: <20231216162639.125215-1-knaerzche@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: <linux-kernel.vger.kernel.org> List-Subscribe: <mailto:linux-kernel+subscribe@vger.kernel.org> List-Unsubscribe: <mailto:linux-kernel+unsubscribe@vger.kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1785456935070051640 X-GMAIL-MSGID: 1785456935070051640 |
Series |
Add HDMI support for RK3128
|
|
Commit Message
Alex Bee
Dec. 16, 2023, 4:26 p.m. UTC
Similar to the othter members of inno_hdmi_connector_state the tmds_rate is
not a property of the device, but of the connector state. Move it to
inno_hdmi_connector_state and make it a long to comply with the clock
framework. To get arround the issue of not having the connector state when
inno_hdmi_i2c_init is called in the bind path, getting the tmds rate is
wrapped in function which returns the fallback rate if the connector
doesn't have a state yet.
Signed-off-by: Alex Bee <knaerzche@gmail.com>
---
changes in v2:
- new patch
drivers/gpu/drm/rockchip/inno_hdmi.c | 36 +++++++++++++++++++---------
1 file changed, 25 insertions(+), 11 deletions(-)
Comments
Hi, On Sat, Dec 16, 2023 at 05:26:30PM +0100, Alex Bee wrote: > Similar to the othter members of inno_hdmi_connector_state the tmds_rate is > not a property of the device, but of the connector state. Move it to > inno_hdmi_connector_state and make it a long to comply with the clock > framework. To get arround the issue of not having the connector state when > inno_hdmi_i2c_init is called in the bind path, getting the tmds rate is > wrapped in function which returns the fallback rate if the connector > doesn't have a state yet. > > Signed-off-by: Alex Bee <knaerzche@gmail.com> > --- > changes in v2: > - new patch > > drivers/gpu/drm/rockchip/inno_hdmi.c | 36 +++++++++++++++++++--------- > 1 file changed, 25 insertions(+), 11 deletions(-) > > diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c > index f9bfae1e97a2..6799d24501b8 100644 > --- a/drivers/gpu/drm/rockchip/inno_hdmi.c > +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c > @@ -47,14 +47,13 @@ struct inno_hdmi { > > struct inno_hdmi_i2c *i2c; > struct i2c_adapter *ddc; > - > - unsigned int tmds_rate; > }; > > struct inno_hdmi_connector_state { > struct drm_connector_state base; > unsigned int enc_out_format; > unsigned int colorimetry; > + unsigned long tmds_rate; > }; > > static struct inno_hdmi *encoder_to_inno_hdmi(struct drm_encoder *encoder) > @@ -133,11 +132,33 @@ static inline void hdmi_modb(struct inno_hdmi *hdmi, u16 offset, > hdmi_writeb(hdmi, offset, temp); > } > > +static unsigned long inno_hdmi_tmds_rate(struct inno_hdmi *hdmi) > +{ > + struct drm_connector *connector = &hdmi->connector; > + struct drm_connector_state *conn_state = connector->state; > + struct inno_hdmi_connector_state *inno_conn_state; > + > + if (conn_state) { > + inno_conn_state = to_inno_hdmi_conn_state(conn_state); > + return inno_conn_state->tmds_rate; > + } > + > + /* > + * When IP controller haven't configured to an accurate video > + * timing, then the TMDS clock source would be switched to > + * PCLK_HDMI, so we need to init the TMDS rate to PCLK rate, > + * and reconfigure the DDC clock. > + */ > + > + return clk_get_rate(hdmi->pclk); > +} > + > static void inno_hdmi_i2c_init(struct inno_hdmi *hdmi) > { > int ddc_bus_freq; > + unsigned long tmds_rate = inno_hdmi_tmds_rate(hdmi); > > - ddc_bus_freq = (hdmi->tmds_rate >> 2) / HDMI_SCL_RATE; > + ddc_bus_freq = (tmds_rate >> 2) / HDMI_SCL_RATE; > > hdmi_writeb(hdmi, DDC_BUS_FREQ_L, ddc_bus_freq & 0xFF); > hdmi_writeb(hdmi, DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF); > @@ -431,7 +452,7 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, > * DCLK_LCDC, so we need to init the TMDS rate to mode pixel > * clock rate, and reconfigure the DDC clock. > */ > - hdmi->tmds_rate = mode->clock * 1000; > + inno_conn_state->tmds_rate = mode->clock * 1000; > inno_hdmi_i2c_init(hdmi); > > /* Unmute video and audio output */ > @@ -823,13 +844,6 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, > goto err_disable_clk; > } > > - /* > - * When IP controller haven't configured to an accurate video > - * timing, then the TMDS clock source would be switched to > - * PCLK_HDMI, so we need to init the TMDS rate to PCLK rate, > - * and reconfigure the DDC clock. > - */ > - hdmi->tmds_rate = clk_get_rate(hdmi->pclk); > inno_hdmi_i2c_init(hdmi); I still think my patch is better there. There's two places that use the inno_hdmi.tmds_rate field: the two callers of inno_hdmi_i2c_init(). One is at bind time and needs to initialise it with a sane default since we don't have a mode set yet, the other is to update the internal clock rate while we have a mode set. Since there's a single "modeset" user, there's no need to store it in the state structure at all: it can be a local variable. And in the bind function, you're not going to use the state structure either since there's no state, and it's just a default that has no relation to the modeset code at all. Your function on the other end tries to reconcile and handle the two. But there's no reason to, it just makes the code harder to follow. Just pass the parent rate you want to init with as an argument and it's easy to read and maintain. Maxime
Am 18.12.23 um 11:06 schrieb Maxime Ripard: > Hi, > > On Sat, Dec 16, 2023 at 05:26:30PM +0100, Alex Bee wrote: >> Similar to the othter members of inno_hdmi_connector_state the tmds_rate is >> not a property of the device, but of the connector state. Move it to >> inno_hdmi_connector_state and make it a long to comply with the clock >> framework. To get arround the issue of not having the connector state when >> inno_hdmi_i2c_init is called in the bind path, getting the tmds rate is >> wrapped in function which returns the fallback rate if the connector >> doesn't have a state yet. >> >> Signed-off-by: Alex Bee <knaerzche@gmail.com> >> --- >> changes in v2: >> - new patch >> >> drivers/gpu/drm/rockchip/inno_hdmi.c | 36 +++++++++++++++++++--------- >> 1 file changed, 25 insertions(+), 11 deletions(-) >> >> diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c >> index f9bfae1e97a2..6799d24501b8 100644 >> --- a/drivers/gpu/drm/rockchip/inno_hdmi.c >> +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c >> @@ -47,14 +47,13 @@ struct inno_hdmi { >> >> struct inno_hdmi_i2c *i2c; >> struct i2c_adapter *ddc; >> - >> - unsigned int tmds_rate; >> }; >> >> struct inno_hdmi_connector_state { >> struct drm_connector_state base; >> unsigned int enc_out_format; >> unsigned int colorimetry; >> + unsigned long tmds_rate; >> }; >> >> static struct inno_hdmi *encoder_to_inno_hdmi(struct drm_encoder *encoder) >> @@ -133,11 +132,33 @@ static inline void hdmi_modb(struct inno_hdmi *hdmi, u16 offset, >> hdmi_writeb(hdmi, offset, temp); >> } >> >> +static unsigned long inno_hdmi_tmds_rate(struct inno_hdmi *hdmi) >> +{ >> + struct drm_connector *connector = &hdmi->connector; >> + struct drm_connector_state *conn_state = connector->state; >> + struct inno_hdmi_connector_state *inno_conn_state; >> + >> + if (conn_state) { >> + inno_conn_state = to_inno_hdmi_conn_state(conn_state); >> + return inno_conn_state->tmds_rate; >> + } >> + >> + /* >> + * When IP controller haven't configured to an accurate video >> + * timing, then the TMDS clock source would be switched to >> + * PCLK_HDMI, so we need to init the TMDS rate to PCLK rate, >> + * and reconfigure the DDC clock. >> + */ >> + >> + return clk_get_rate(hdmi->pclk); >> +} >> + >> static void inno_hdmi_i2c_init(struct inno_hdmi *hdmi) >> { >> int ddc_bus_freq; >> + unsigned long tmds_rate = inno_hdmi_tmds_rate(hdmi); >> >> - ddc_bus_freq = (hdmi->tmds_rate >> 2) / HDMI_SCL_RATE; >> + ddc_bus_freq = (tmds_rate >> 2) / HDMI_SCL_RATE; >> >> hdmi_writeb(hdmi, DDC_BUS_FREQ_L, ddc_bus_freq & 0xFF); >> hdmi_writeb(hdmi, DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF); >> @@ -431,7 +452,7 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, >> * DCLK_LCDC, so we need to init the TMDS rate to mode pixel >> * clock rate, and reconfigure the DDC clock. >> */ >> - hdmi->tmds_rate = mode->clock * 1000; >> + inno_conn_state->tmds_rate = mode->clock * 1000; >> inno_hdmi_i2c_init(hdmi); >> >> /* Unmute video and audio output */ >> @@ -823,13 +844,6 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, >> goto err_disable_clk; >> } >> >> - /* >> - * When IP controller haven't configured to an accurate video >> - * timing, then the TMDS clock source would be switched to >> - * PCLK_HDMI, so we need to init the TMDS rate to PCLK rate, >> - * and reconfigure the DDC clock. >> - */ >> - hdmi->tmds_rate = clk_get_rate(hdmi->pclk); >> inno_hdmi_i2c_init(hdmi); > I still think my patch is better there. > > There's two places that use the inno_hdmi.tmds_rate field: the two > callers of inno_hdmi_i2c_init(). One is at bind time and needs to > initialise it with a sane default since we don't have a mode set yet, > the other is to update the internal clock rate while we have a mode set. That’s, unfortunately, not fully true: inno_hdmi_set_pwr_mode not only called at mode_set-time, but also in inno_hdmi_reset which is called in the bind path (where we do not have a mode). That’s the point why I thought extracting this in function makes sense. Otherwise I would have to pass the tmds_rate to inno_hdmi_set_pwr_mode (also for the LOWER_PWR-case where I don't need it) or do that whole fallback-if-no-mode thing in inno_hdmi_set_pwr_mode directly. Neither would make the code easier to follow. Being able to use it in inno_hdmi_i2c_init also is a nice gimmick. I agree, having it in the custom connector state is not strictly required, but I'd really like to keep the wrapping function. Alex > Since there's a single "modeset" user, there's no need to store it in > the state structure at all: it can be a local variable. > > And in the bind function, you're not going to use the state structure > either since there's no state, and it's just a default that has no > relation to the modeset code at all. > > Your function on the other end tries to reconcile and handle the two. > But there's no reason to, it just makes the code harder to follow. Just > pass the parent rate you want to init with as an argument and it's easy > to read and maintain. > > Maxime
Hi Maxime, Am 18.12.23 um 13:49 schrieb Alex Bee: > > Am 18.12.23 um 11:06 schrieb Maxime Ripard: >> Hi, >> >> On Sat, Dec 16, 2023 at 05:26:30PM +0100, Alex Bee wrote: >>> Similar to the othter members of inno_hdmi_connector_state the >>> tmds_rate is >>> not a property of the device, but of the connector state. Move it to >>> inno_hdmi_connector_state and make it a long to comply with the clock >>> framework. To get arround the issue of not having the connector >>> state when >>> inno_hdmi_i2c_init is called in the bind path, getting the tmds rate is >>> wrapped in function which returns the fallback rate if the connector >>> doesn't have a state yet. >>> >>> Signed-off-by: Alex Bee <knaerzche@gmail.com> >>> --- >>> changes in v2: >>> - new patch >>> >>> drivers/gpu/drm/rockchip/inno_hdmi.c | 36 >>> +++++++++++++++++++--------- >>> 1 file changed, 25 insertions(+), 11 deletions(-) >>> >>> diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c >>> b/drivers/gpu/drm/rockchip/inno_hdmi.c >>> index f9bfae1e97a2..6799d24501b8 100644 >>> --- a/drivers/gpu/drm/rockchip/inno_hdmi.c >>> +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c >>> @@ -47,14 +47,13 @@ struct inno_hdmi { >>> struct inno_hdmi_i2c *i2c; >>> struct i2c_adapter *ddc; >>> - >>> - unsigned int tmds_rate; >>> }; >>> struct inno_hdmi_connector_state { >>> struct drm_connector_state base; >>> unsigned int enc_out_format; >>> unsigned int colorimetry; >>> + unsigned long tmds_rate; >>> }; >>> static struct inno_hdmi *encoder_to_inno_hdmi(struct drm_encoder >>> *encoder) >>> @@ -133,11 +132,33 @@ static inline void hdmi_modb(struct inno_hdmi >>> *hdmi, u16 offset, >>> hdmi_writeb(hdmi, offset, temp); >>> } >>> +static unsigned long inno_hdmi_tmds_rate(struct inno_hdmi *hdmi) >>> +{ >>> + struct drm_connector *connector = &hdmi->connector; >>> + struct drm_connector_state *conn_state = connector->state; >>> + struct inno_hdmi_connector_state *inno_conn_state; >>> + >>> + if (conn_state) { >>> + inno_conn_state = to_inno_hdmi_conn_state(conn_state); >>> + return inno_conn_state->tmds_rate; >>> + } >>> + >>> + /* >>> + * When IP controller haven't configured to an accurate video >>> + * timing, then the TMDS clock source would be switched to >>> + * PCLK_HDMI, so we need to init the TMDS rate to PCLK rate, >>> + * and reconfigure the DDC clock. >>> + */ >>> + >>> + return clk_get_rate(hdmi->pclk); >>> +} >>> + >>> static void inno_hdmi_i2c_init(struct inno_hdmi *hdmi) >>> { >>> int ddc_bus_freq; >>> + unsigned long tmds_rate = inno_hdmi_tmds_rate(hdmi); >>> - ddc_bus_freq = (hdmi->tmds_rate >> 2) / HDMI_SCL_RATE; >>> + ddc_bus_freq = (tmds_rate >> 2) / HDMI_SCL_RATE; >>> hdmi_writeb(hdmi, DDC_BUS_FREQ_L, ddc_bus_freq & 0xFF); >>> hdmi_writeb(hdmi, DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF); >>> @@ -431,7 +452,7 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, >>> * DCLK_LCDC, so we need to init the TMDS rate to mode pixel >>> * clock rate, and reconfigure the DDC clock. >>> */ >>> - hdmi->tmds_rate = mode->clock * 1000; >>> + inno_conn_state->tmds_rate = mode->clock * 1000; >>> inno_hdmi_i2c_init(hdmi); >>> /* Unmute video and audio output */ >>> @@ -823,13 +844,6 @@ static int inno_hdmi_bind(struct device *dev, >>> struct device *master, >>> goto err_disable_clk; >>> } >>> - /* >>> - * When IP controller haven't configured to an accurate video >>> - * timing, then the TMDS clock source would be switched to >>> - * PCLK_HDMI, so we need to init the TMDS rate to PCLK rate, >>> - * and reconfigure the DDC clock. >>> - */ >>> - hdmi->tmds_rate = clk_get_rate(hdmi->pclk); >>> inno_hdmi_i2c_init(hdmi); >> I still think my patch is better there. >> I found a way now and added your patch which removes the tmds_rate: I noticed powering up the phy initially isn't necessary at all (and makes no sense). I refactored inno_hdmi_set_pwr_mode in two functions (in a similar way you did for the infoframe), so that the tmds rate (pixelclock) is only needed as parameter when a mode is set. Alex >> There's two places that use the inno_hdmi.tmds_rate field: the two >> callers of inno_hdmi_i2c_init(). One is at bind time and needs to >> initialise it with a sane default since we don't have a mode set yet, >> the other is to update the internal clock rate while we have a mode set. > That’s, unfortunately, not fully true: inno_hdmi_set_pwr_mode not only > called at mode_set-time, but also in inno_hdmi_reset which is called > in the > bind path (where we do not have a mode). That’s the point why I thought > extracting this in function makes sense. Otherwise I would have to > pass the > tmds_rate to inno_hdmi_set_pwr_mode (also for the LOWER_PWR-case where I > don't need it) or do that whole fallback-if-no-mode thing in > inno_hdmi_set_pwr_mode directly. Neither would make the code easier to > follow. Being able to use it in inno_hdmi_i2c_init also is a nice > gimmick. > I agree, having it in the custom connector state is not strictly > required, > but I'd really like to keep the wrapping function. > > Alex > >> Since there's a single "modeset" user, there's no need to store it in >> the state structure at all: it can be a local variable. >> >> And in the bind function, you're not going to use the state structure >> either since there's no state, and it's just a default that has no >> relation to the modeset code at all. >> >> Your function on the other end tries to reconcile and handle the two. >> But there's no reason to, it just makes the code harder to follow. Just >> pass the parent rate you want to init with as an argument and it's easy >> to read and maintain. >> >> Maxime
diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index f9bfae1e97a2..6799d24501b8 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -47,14 +47,13 @@ struct inno_hdmi { struct inno_hdmi_i2c *i2c; struct i2c_adapter *ddc; - - unsigned int tmds_rate; }; struct inno_hdmi_connector_state { struct drm_connector_state base; unsigned int enc_out_format; unsigned int colorimetry; + unsigned long tmds_rate; }; static struct inno_hdmi *encoder_to_inno_hdmi(struct drm_encoder *encoder) @@ -133,11 +132,33 @@ static inline void hdmi_modb(struct inno_hdmi *hdmi, u16 offset, hdmi_writeb(hdmi, offset, temp); } +static unsigned long inno_hdmi_tmds_rate(struct inno_hdmi *hdmi) +{ + struct drm_connector *connector = &hdmi->connector; + struct drm_connector_state *conn_state = connector->state; + struct inno_hdmi_connector_state *inno_conn_state; + + if (conn_state) { + inno_conn_state = to_inno_hdmi_conn_state(conn_state); + return inno_conn_state->tmds_rate; + } + + /* + * When IP controller haven't configured to an accurate video + * timing, then the TMDS clock source would be switched to + * PCLK_HDMI, so we need to init the TMDS rate to PCLK rate, + * and reconfigure the DDC clock. + */ + + return clk_get_rate(hdmi->pclk); +} + static void inno_hdmi_i2c_init(struct inno_hdmi *hdmi) { int ddc_bus_freq; + unsigned long tmds_rate = inno_hdmi_tmds_rate(hdmi); - ddc_bus_freq = (hdmi->tmds_rate >> 2) / HDMI_SCL_RATE; + ddc_bus_freq = (tmds_rate >> 2) / HDMI_SCL_RATE; hdmi_writeb(hdmi, DDC_BUS_FREQ_L, ddc_bus_freq & 0xFF); hdmi_writeb(hdmi, DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF); @@ -431,7 +452,7 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, * DCLK_LCDC, so we need to init the TMDS rate to mode pixel * clock rate, and reconfigure the DDC clock. */ - hdmi->tmds_rate = mode->clock * 1000; + inno_conn_state->tmds_rate = mode->clock * 1000; inno_hdmi_i2c_init(hdmi); /* Unmute video and audio output */ @@ -823,13 +844,6 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, goto err_disable_clk; } - /* - * When IP controller haven't configured to an accurate video - * timing, then the TMDS clock source would be switched to - * PCLK_HDMI, so we need to init the TMDS rate to PCLK rate, - * and reconfigure the DDC clock. - */ - hdmi->tmds_rate = clk_get_rate(hdmi->pclk); inno_hdmi_i2c_init(hdmi); ret = inno_hdmi_register(drm, hdmi);