[PATCH 2/2] drm/bridge: tc358767: Add DPI to eDP bridge driver

Archit Taneja architt at codeaurora.org
Mon Jul 11 08:32:19 UTC 2016



On 07/05/2016 01:30 PM, Philipp Zabel wrote:
> Hi Archit,
>
> thanks for the review!
>
> Am Dienstag, den 05.07.2016, 10:08 +0530 schrieb Archit Taneja:
> [...]
>>> +#include <drm/drmP.h>
>>
>> This may not be needed.
>
> I'll check and remove it.
>
>>> +#ifndef regmap_read_poll_timeout
>>> +#define regmap_read_poll_timeout(map, addr, val, cond, sleep_us, timeout_us) \
>>> +({ \
>>> +	ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \
>>> +	int ret; \
>>> +	might_sleep_if(sleep_us); \
>>> +	for (;;) { \
>>> +		ret = regmap_read((map), (addr), &(val)); \
>>> +		if (ret) \
>>> +			break; \
>>> +		if (cond) \
>>> +			break; \
>>> +		if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) { \
>>> +			ret = regmap_read((map), (addr), &(val)); \
>>> +			break; \
>>> +		} \
>>> +		if (sleep_us) \
>>> +			usleep_range((sleep_us >> 2) + 1, sleep_us); \
>>> +	} \
>>> +	ret ?: ((cond) ? 0 : -ETIMEDOUT); \
>>> +})
>>> +#endif
>>
>> Is there a reason why this is wrapped around a #ifndef? I don't see it
>> in the current regmap.h headers. It would also be nice if it were made
>> into a function.
>
> This is a macro similar to those defined in iopoll.h. It can't be a
> function because the "cond"ition is specified by the caller and has to
> be evaluated in the loop.
> I'll submit this for regmap. If it doesn't get accepted I'll change this
> into two properly named functions.
>
> [...]
>>> +static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk)
>>> +{
>>> +	int ret;
>>> +	int i_pre, best_pre = 1;
>>> +	int i_post, best_post = 1;
>>> +	int div, best_div = 1;
>>> +	int mul, best_mul = 1;
>>> +	int delta, best_delta;
>>> +	int ext_div[] = {1, 2, 3, 5, 7};
>>> +	int best_pixelclock = 0;
>>> +	int vco_hi = 0;
>>> +	int pixelclock;
>>> +
>>> +	pixelclock = tc->pll_clk;
>>> +
>>> +	dev_dbg(tc->dev, "PLL: requested %d pixelclock, ref %d\n", pixelclock,
>>> +		refclk);
>>> +	best_delta = pixelclock;
>>> +	/* big loops */
>>
>> The above comment could be improved.
>
> Will do.
>
>>> +	for (i_pre = 0; i_pre < ARRAY_SIZE(ext_div); i_pre++) {
>>> +		/* refclk / ext_pre_div should be in the 1 to 200 MHz range */
>>> +		if ((refclk / ext_div[i_pre] > 200000000) ||
>>
>> The > 200 Mhz check seems redundant, since no refclk beyond 38.4 Mhz is
>> supported.
>
> Indeed. I'll drop the check and update the comment.
>
>>> +		    (refclk / ext_div[i_pre] < 1000000))
>>> +			continue;
>>> +		for (i_post = 0; i_post < ARRAY_SIZE(ext_div); i_post++) {
>>> +			for (div = 1; div <= 16; div++) {
>>> +				u32 clk;
>>> +				u64 tmp;
>>> +
>>> +				tmp = pixelclock * ext_div[i_pre] *
>>> +				      ext_div[i_post] * div;
>>> +				do_div(tmp, refclk);
>>> +				mul = tmp;
>>> +
>>> +				clk = refclk / ext_div[i_pre] / div * mul /
>>> +				      ext_div[i_post];
>>
>> Some braces for the above expression might help :)
>
> Ok.
>
>>> +				delta = clk - pixelclock;
>>> +
>>> +				/* check limits */
>>> +				if ((mul < 1) ||
>>> +				    (mul > 128))
>>
>> minor comment: the above check could be in a single line.
>
> Oversight, will fix.
>
> [...]
>>> +static int tc_aux_link_setup(struct tc_data *tc)
>>> +{
>>> +	unsigned long rate;
>>> +	u32 value;
>>> +	int ret;
>>> +
>>> +	rate = clk_get_rate(tc->refclk);
>>
>> Ah, you can discard my comment on the clock binding in the DT patch.
>> I guess you needed it to figure out the rate.
>
> Alright, going back to the other mail and updating my answer.
>
>>> +	switch (rate) {
>>> +	case 38400000:
>>> +		value = REF_FREQ_38M4;
>>> +		break;
>>> +	case 26000000:
>>> +		value = REF_FREQ_26M;
>>> +		break;
>>> +	case 19200000:
>>> +		value = REF_FREQ_19M2;
>>> +		break;
>>> +	case 13000000:
>>> +		value = REF_FREQ_13M;
>>> +		break;
>>> +	default:
>>> +		dev_err(tc->dev, "Invalid refclk rate: %lu Hz\n", rate);
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	/* Setup DP-PHY / PLL */
>>> +	value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
>>> +	tc_write(SYS_PLLPARAM, value);
>>> +
>>> +	tc_write(DP_PHY_CTRL, BGREN | PWR_SW_EN | BIT(2) | PHY_A0_EN);
>>
>> It seems a bit strange to have BIT(2) besides the other predefined
>> macros.
>
> I accidentally lost the comment when shortening this, BIT(2) is reserved
> but set.
>
> [...]
>>> +	/* PXL PLL setup */
>>> +	if (tc->test_pattern) {
>>
>> I couldn't find out who is setting tc->test_pattern. Is it always
>> 0?
>
> Hm, you are right. I wonder what a good mechanism would be to enable a
> test pattern for a bridge driver. Module parameters? We don't have
> anyhting like V4L2_CID_TEST_PATTERN in drm. I could also drop test
> pattern support from the initial patch and submit it separately.

Module parameter sounds like a good option. Although, it seems like the
pll is enabled only when test_pattern is set. How does the bridge work
if the pll isn't enabled?

Archit

>
> [...]
>>> +static const struct drm_connector_helper_funcs tc_connector_helper_funcs = {
>>> +	.get_modes = tc_connector_get_modes,
>>> +	.mode_valid = tc_connector_mode_valid,
>>> +	.best_encoder = tc_connector_best_encoder,
>>> +};
>>> +
>>> +static void tc_connector_destroy(struct drm_connector *connector)
>>> +{
>>> +	drm_connector_unregister(connector);
>>> +	drm_connector_cleanup(connector);
>>> +}
>>> +
>>> +static const struct drm_connector_funcs tc_connector_funcs = {
>>> +	.dpms = drm_helper_connector_dpms,
>>> +	.fill_modes = drm_helper_probe_single_connector_modes,
>>> +	.detect = tc_connector_detect,
>>> +	.destroy = tc_connector_destroy,
>>
>> Can we use atomic helpers where applicable?
>
> I have worked on this on i.MX6, which doesn't have atomic support merged
> yet. I'll test with Liu Ying's i.MX6 atomic modeset patches and update
> to atomic helpers here.
>
> regards
> Philipp
>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


More information about the dri-devel mailing list