brintos

brintos / linux-shallow public Read only

0
0
Text · 15.2 KiB · 030f997 Raw
746 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2009 Nokia Corporation4 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>5 *6 * Some code and ideas taken from drivers/video/omap/ driver7 * by Imre Deak.8 */9 10#define DSS_SUBSYS_NAME "DPI"11 12#include <linux/clk.h>13#include <linux/delay.h>14#include <linux/err.h>15#include <linux/errno.h>16#include <linux/export.h>17#include <linux/kernel.h>18#include <linux/of.h>19#include <linux/platform_device.h>20#include <linux/regulator/consumer.h>21#include <linux/string.h>22#include <linux/sys_soc.h>23 24#include <drm/drm_bridge.h>25 26#include "dss.h"27#include "omapdss.h"28 29struct dpi_data {30	struct platform_device *pdev;31	enum dss_model dss_model;32	struct dss_device *dss;33	unsigned int id;34 35	struct regulator *vdds_dsi_reg;36	enum dss_clk_source clk_src;37	struct dss_pll *pll;38 39	struct dss_lcd_mgr_config mgr_config;40	unsigned long pixelclock;41	int data_lines;42 43	struct omap_dss_device output;44	struct drm_bridge bridge;45};46 47#define drm_bridge_to_dpi(bridge) container_of(bridge, struct dpi_data, bridge)48 49/* -----------------------------------------------------------------------------50 * Clock Handling and PLL51 */52 53static enum dss_clk_source dpi_get_clk_src_dra7xx(struct dpi_data *dpi,54						  enum omap_channel channel)55{56	/*57	 * Possible clock sources:58	 * LCD1: FCK/PLL1_1/HDMI_PLL59	 * LCD2: FCK/PLL1_3/HDMI_PLL (DRA74x: PLL2_3)60	 * LCD3: FCK/PLL1_3/HDMI_PLL (DRA74x: PLL2_1)61	 */62 63	switch (channel) {64	case OMAP_DSS_CHANNEL_LCD:65	{66		if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_1))67			return DSS_CLK_SRC_PLL1_1;68		break;69	}70	case OMAP_DSS_CHANNEL_LCD2:71	{72		if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_3))73			return DSS_CLK_SRC_PLL1_3;74		if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL2_3))75			return DSS_CLK_SRC_PLL2_3;76		break;77	}78	case OMAP_DSS_CHANNEL_LCD3:79	{80		if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL2_1))81			return DSS_CLK_SRC_PLL2_1;82		if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_3))83			return DSS_CLK_SRC_PLL1_3;84		break;85	}86	default:87		break;88	}89 90	return DSS_CLK_SRC_FCK;91}92 93static enum dss_clk_source dpi_get_clk_src(struct dpi_data *dpi)94{95	enum omap_channel channel = dpi->output.dispc_channel;96 97	/*98	 * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL99	 * would also be used for DISPC fclk. Meaning, when the DPI output is100	 * disabled, DISPC clock will be disabled, and TV out will stop.101	 */102	switch (dpi->dss_model) {103	case DSS_MODEL_OMAP2:104	case DSS_MODEL_OMAP3:105		return DSS_CLK_SRC_FCK;106 107	case DSS_MODEL_OMAP4:108		switch (channel) {109		case OMAP_DSS_CHANNEL_LCD:110			return DSS_CLK_SRC_PLL1_1;111		case OMAP_DSS_CHANNEL_LCD2:112			return DSS_CLK_SRC_PLL2_1;113		default:114			return DSS_CLK_SRC_FCK;115		}116 117	case DSS_MODEL_OMAP5:118		switch (channel) {119		case OMAP_DSS_CHANNEL_LCD:120			return DSS_CLK_SRC_PLL1_1;121		case OMAP_DSS_CHANNEL_LCD3:122			return DSS_CLK_SRC_PLL2_1;123		case OMAP_DSS_CHANNEL_LCD2:124		default:125			return DSS_CLK_SRC_FCK;126		}127 128	case DSS_MODEL_DRA7:129		return dpi_get_clk_src_dra7xx(dpi, channel);130 131	default:132		return DSS_CLK_SRC_FCK;133	}134}135 136struct dpi_clk_calc_ctx {137	struct dpi_data *dpi;138	unsigned int clkout_idx;139 140	/* inputs */141 142	unsigned long pck_min, pck_max;143 144	/* outputs */145 146	struct dss_pll_clock_info pll_cinfo;147	unsigned long fck;148	struct dispc_clock_info dispc_cinfo;149};150 151static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,152		unsigned long pck, void *data)153{154	struct dpi_clk_calc_ctx *ctx = data;155 156	/*157	 * Odd dividers give us uneven duty cycle, causing problem when level158	 * shifted. So skip all odd dividers when the pixel clock is on the159	 * higher side.160	 */161	if (ctx->pck_min >= 100000000) {162		if (lckd > 1 && lckd % 2 != 0)163			return false;164 165		if (pckd > 1 && pckd % 2 != 0)166			return false;167	}168 169	ctx->dispc_cinfo.lck_div = lckd;170	ctx->dispc_cinfo.pck_div = pckd;171	ctx->dispc_cinfo.lck = lck;172	ctx->dispc_cinfo.pck = pck;173 174	return true;175}176 177 178static bool dpi_calc_hsdiv_cb(int m_dispc, unsigned long dispc,179		void *data)180{181	struct dpi_clk_calc_ctx *ctx = data;182 183	ctx->pll_cinfo.mX[ctx->clkout_idx] = m_dispc;184	ctx->pll_cinfo.clkout[ctx->clkout_idx] = dispc;185 186	return dispc_div_calc(ctx->dpi->dss->dispc, dispc,187			      ctx->pck_min, ctx->pck_max,188			      dpi_calc_dispc_cb, ctx);189}190 191 192static bool dpi_calc_pll_cb(int n, int m, unsigned long fint,193		unsigned long clkdco,194		void *data)195{196	struct dpi_clk_calc_ctx *ctx = data;197 198	ctx->pll_cinfo.n = n;199	ctx->pll_cinfo.m = m;200	ctx->pll_cinfo.fint = fint;201	ctx->pll_cinfo.clkdco = clkdco;202 203	return dss_pll_hsdiv_calc_a(ctx->dpi->pll, clkdco,204		ctx->pck_min, dss_get_max_fck_rate(ctx->dpi->dss),205		dpi_calc_hsdiv_cb, ctx);206}207 208static bool dpi_calc_dss_cb(unsigned long fck, void *data)209{210	struct dpi_clk_calc_ctx *ctx = data;211 212	ctx->fck = fck;213 214	return dispc_div_calc(ctx->dpi->dss->dispc, fck,215			      ctx->pck_min, ctx->pck_max,216			      dpi_calc_dispc_cb, ctx);217}218 219static bool dpi_pll_clk_calc(struct dpi_data *dpi, unsigned long pck,220		struct dpi_clk_calc_ctx *ctx)221{222	unsigned long clkin;223 224	memset(ctx, 0, sizeof(*ctx));225	ctx->dpi = dpi;226	ctx->clkout_idx = dss_pll_get_clkout_idx_for_src(dpi->clk_src);227 228	clkin = clk_get_rate(dpi->pll->clkin);229 230	if (dpi->pll->hw->type == DSS_PLL_TYPE_A) {231		unsigned long pll_min, pll_max;232 233		ctx->pck_min = pck - 1000;234		ctx->pck_max = pck + 1000;235 236		pll_min = 0;237		pll_max = 0;238 239		return dss_pll_calc_a(ctx->dpi->pll, clkin,240				pll_min, pll_max,241				dpi_calc_pll_cb, ctx);242	} else { /* DSS_PLL_TYPE_B */243		dss_pll_calc_b(dpi->pll, clkin, pck, &ctx->pll_cinfo);244 245		ctx->dispc_cinfo.lck_div = 1;246		ctx->dispc_cinfo.pck_div = 1;247		ctx->dispc_cinfo.lck = ctx->pll_cinfo.clkout[0];248		ctx->dispc_cinfo.pck = ctx->dispc_cinfo.lck;249 250		return true;251	}252}253 254static bool dpi_dss_clk_calc(struct dpi_data *dpi, unsigned long pck,255			     struct dpi_clk_calc_ctx *ctx)256{257	int i;258 259	/*260	 * DSS fck gives us very few possibilities, so finding a good pixel261	 * clock may not be possible. We try multiple times to find the clock,262	 * each time widening the pixel clock range we look for, up to263	 * +/- ~15MHz.264	 */265 266	for (i = 0; i < 25; ++i) {267		bool ok;268 269		memset(ctx, 0, sizeof(*ctx));270		ctx->dpi = dpi;271		if (pck > 1000 * i * i * i)272			ctx->pck_min = max(pck - 1000 * i * i * i, 0lu);273		else274			ctx->pck_min = 0;275		ctx->pck_max = pck + 1000 * i * i * i;276 277		ok = dss_div_calc(dpi->dss, pck, ctx->pck_min,278				  dpi_calc_dss_cb, ctx);279		if (ok)280			return ok;281	}282 283	return false;284}285 286 287 288static int dpi_set_pll_clk(struct dpi_data *dpi, unsigned long pck_req)289{290	struct dpi_clk_calc_ctx ctx;291	int r;292	bool ok;293 294	ok = dpi_pll_clk_calc(dpi, pck_req, &ctx);295	if (!ok)296		return -EINVAL;297 298	r = dss_pll_set_config(dpi->pll, &ctx.pll_cinfo);299	if (r)300		return r;301 302	dss_select_lcd_clk_source(dpi->dss, dpi->output.dispc_channel,303				  dpi->clk_src);304 305	dpi->mgr_config.clock_info = ctx.dispc_cinfo;306 307	return 0;308}309 310static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req)311{312	struct dpi_clk_calc_ctx ctx;313	int r;314	bool ok;315 316	ok = dpi_dss_clk_calc(dpi, pck_req, &ctx);317	if (!ok)318		return -EINVAL;319 320	r = dss_set_fck_rate(dpi->dss, ctx.fck);321	if (r)322		return r;323 324	dpi->mgr_config.clock_info = ctx.dispc_cinfo;325 326	return 0;327}328 329static int dpi_set_mode(struct dpi_data *dpi)330{331	int r;332 333	if (dpi->pll)334		r = dpi_set_pll_clk(dpi, dpi->pixelclock);335	else336		r = dpi_set_dispc_clk(dpi, dpi->pixelclock);337 338	return r;339}340 341static void dpi_config_lcd_manager(struct dpi_data *dpi)342{343	dpi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;344 345	dpi->mgr_config.stallmode = false;346	dpi->mgr_config.fifohandcheck = false;347 348	dpi->mgr_config.video_port_width = dpi->data_lines;349 350	dpi->mgr_config.lcden_sig_polarity = 0;351 352	dss_mgr_set_lcd_config(&dpi->output, &dpi->mgr_config);353}354 355static int dpi_clock_update(struct dpi_data *dpi, unsigned long *clock)356{357	int lck_div, pck_div;358	unsigned long fck;359	struct dpi_clk_calc_ctx ctx;360 361	if (dpi->pll) {362		if (!dpi_pll_clk_calc(dpi, *clock, &ctx))363			return -EINVAL;364 365		fck = ctx.pll_cinfo.clkout[ctx.clkout_idx];366	} else {367		if (!dpi_dss_clk_calc(dpi, *clock, &ctx))368			return -EINVAL;369 370		fck = ctx.fck;371	}372 373	lck_div = ctx.dispc_cinfo.lck_div;374	pck_div = ctx.dispc_cinfo.pck_div;375 376	*clock = fck / lck_div / pck_div;377 378	return 0;379}380 381static int dpi_verify_pll(struct dss_pll *pll)382{383	int r;384 385	/* do initial setup with the PLL to see if it is operational */386 387	r = dss_pll_enable(pll);388	if (r)389		return r;390 391	dss_pll_disable(pll);392 393	return 0;394}395 396static void dpi_init_pll(struct dpi_data *dpi)397{398	struct dss_pll *pll;399 400	if (dpi->pll)401		return;402 403	dpi->clk_src = dpi_get_clk_src(dpi);404 405	pll = dss_pll_find_by_src(dpi->dss, dpi->clk_src);406	if (!pll)407		return;408 409	if (dpi_verify_pll(pll)) {410		DSSWARN("PLL not operational\n");411		return;412	}413 414	dpi->pll = pll;415}416 417/* -----------------------------------------------------------------------------418 * DRM Bridge Operations419 */420 421static int dpi_bridge_attach(struct drm_bridge *bridge,422			     enum drm_bridge_attach_flags flags)423{424	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);425 426	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))427		return -EINVAL;428 429	dpi_init_pll(dpi);430 431	return drm_bridge_attach(bridge->encoder, dpi->output.next_bridge,432				 bridge, flags);433}434 435static enum drm_mode_status436dpi_bridge_mode_valid(struct drm_bridge *bridge,437		       const struct drm_display_info *info,438		       const struct drm_display_mode *mode)439{440	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);441	unsigned long clock = mode->clock * 1000;442	int ret;443 444	if (mode->hdisplay % 8 != 0)445		return MODE_BAD_WIDTH;446 447	if (mode->clock == 0)448		return MODE_NOCLOCK;449 450	ret = dpi_clock_update(dpi, &clock);451	if (ret < 0)452		return MODE_CLOCK_RANGE;453 454	return MODE_OK;455}456 457static bool dpi_bridge_mode_fixup(struct drm_bridge *bridge,458				   const struct drm_display_mode *mode,459				   struct drm_display_mode *adjusted_mode)460{461	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);462	unsigned long clock = mode->clock * 1000;463	int ret;464 465	ret = dpi_clock_update(dpi, &clock);466	if (ret < 0)467		return false;468 469	adjusted_mode->clock = clock / 1000;470 471	return true;472}473 474static void dpi_bridge_mode_set(struct drm_bridge *bridge,475				 const struct drm_display_mode *mode,476				 const struct drm_display_mode *adjusted_mode)477{478	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);479 480	dpi->pixelclock = adjusted_mode->clock * 1000;481}482 483static void dpi_bridge_enable(struct drm_bridge *bridge)484{485	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);486	int r;487 488	if (dpi->vdds_dsi_reg) {489		r = regulator_enable(dpi->vdds_dsi_reg);490		if (r)491			return;492	}493 494	r = dispc_runtime_get(dpi->dss->dispc);495	if (r)496		goto err_get_dispc;497 498	r = dss_dpi_select_source(dpi->dss, dpi->id, dpi->output.dispc_channel);499	if (r)500		goto err_src_sel;501 502	if (dpi->pll) {503		r = dss_pll_enable(dpi->pll);504		if (r)505			goto err_pll_init;506	}507 508	r = dpi_set_mode(dpi);509	if (r)510		goto err_set_mode;511 512	dpi_config_lcd_manager(dpi);513 514	mdelay(2);515 516	r = dss_mgr_enable(&dpi->output);517	if (r)518		goto err_mgr_enable;519 520	return;521 522err_mgr_enable:523err_set_mode:524	if (dpi->pll)525		dss_pll_disable(dpi->pll);526err_pll_init:527err_src_sel:528	dispc_runtime_put(dpi->dss->dispc);529err_get_dispc:530	if (dpi->vdds_dsi_reg)531		regulator_disable(dpi->vdds_dsi_reg);532}533 534static void dpi_bridge_disable(struct drm_bridge *bridge)535{536	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);537 538	dss_mgr_disable(&dpi->output);539 540	if (dpi->pll) {541		dss_select_lcd_clk_source(dpi->dss, dpi->output.dispc_channel,542					  DSS_CLK_SRC_FCK);543		dss_pll_disable(dpi->pll);544	}545 546	dispc_runtime_put(dpi->dss->dispc);547 548	if (dpi->vdds_dsi_reg)549		regulator_disable(dpi->vdds_dsi_reg);550}551 552static const struct drm_bridge_funcs dpi_bridge_funcs = {553	.attach = dpi_bridge_attach,554	.mode_valid = dpi_bridge_mode_valid,555	.mode_fixup = dpi_bridge_mode_fixup,556	.mode_set = dpi_bridge_mode_set,557	.enable = dpi_bridge_enable,558	.disable = dpi_bridge_disable,559};560 561static void dpi_bridge_init(struct dpi_data *dpi)562{563	dpi->bridge.funcs = &dpi_bridge_funcs;564	dpi->bridge.of_node = dpi->pdev->dev.of_node;565	dpi->bridge.type = DRM_MODE_CONNECTOR_DPI;566 567	drm_bridge_add(&dpi->bridge);568}569 570static void dpi_bridge_cleanup(struct dpi_data *dpi)571{572	drm_bridge_remove(&dpi->bridge);573}574 575/* -----------------------------------------------------------------------------576 * Initialisation and Cleanup577 */578 579/*580 * Return a hardcoded channel for the DPI output. This should work for581 * current use cases, but this can be later expanded to either resolve582 * the channel in some more dynamic manner, or get the channel as a user583 * parameter.584 */585static enum omap_channel dpi_get_channel(struct dpi_data *dpi)586{587	switch (dpi->dss_model) {588	case DSS_MODEL_OMAP2:589	case DSS_MODEL_OMAP3:590		return OMAP_DSS_CHANNEL_LCD;591 592	case DSS_MODEL_DRA7:593		switch (dpi->id) {594		case 2:595			return OMAP_DSS_CHANNEL_LCD3;596		case 1:597			return OMAP_DSS_CHANNEL_LCD2;598		case 0:599		default:600			return OMAP_DSS_CHANNEL_LCD;601		}602 603	case DSS_MODEL_OMAP4:604		return OMAP_DSS_CHANNEL_LCD2;605 606	case DSS_MODEL_OMAP5:607		return OMAP_DSS_CHANNEL_LCD3;608 609	default:610		DSSWARN("unsupported DSS version\n");611		return OMAP_DSS_CHANNEL_LCD;612	}613}614 615static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)616{617	struct omap_dss_device *out = &dpi->output;618	u32 port_num = 0;619	int r;620 621	dpi_bridge_init(dpi);622 623	of_property_read_u32(port, "reg", &port_num);624	dpi->id = port_num <= 2 ? port_num : 0;625 626	switch (port_num) {627	case 2:628		out->name = "dpi.2";629		break;630	case 1:631		out->name = "dpi.1";632		break;633	case 0:634	default:635		out->name = "dpi.0";636		break;637	}638 639	out->dev = &dpi->pdev->dev;640	out->id = OMAP_DSS_OUTPUT_DPI;641	out->type = OMAP_DISPLAY_TYPE_DPI;642	out->dispc_channel = dpi_get_channel(dpi);643	out->of_port = port_num;644 645	r = omapdss_device_init_output(out, &dpi->bridge);646	if (r < 0) {647		dpi_bridge_cleanup(dpi);648		return r;649	}650 651	omapdss_device_register(out);652 653	return 0;654}655 656static void dpi_uninit_output_port(struct device_node *port)657{658	struct dpi_data *dpi = port->data;659	struct omap_dss_device *out = &dpi->output;660 661	omapdss_device_unregister(out);662	omapdss_device_cleanup_output(out);663 664	dpi_bridge_cleanup(dpi);665}666 667/* -----------------------------------------------------------------------------668 * Initialisation and Cleanup669 */670 671static const struct soc_device_attribute dpi_soc_devices[] = {672	{ .machine = "OMAP3[456]*" },673	{ .machine = "[AD]M37*" },674	{ /* sentinel */ }675};676 677static int dpi_init_regulator(struct dpi_data *dpi)678{679	struct regulator *vdds_dsi;680 681	/*682	 * The DPI uses the DSI VDDS on OMAP34xx, OMAP35xx, OMAP36xx, AM37xx and683	 * DM37xx only.684	 */685	if (!soc_device_match(dpi_soc_devices))686		return 0;687 688	vdds_dsi = devm_regulator_get(&dpi->pdev->dev, "vdds_dsi");689	if (IS_ERR(vdds_dsi)) {690		if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)691			DSSERR("can't get VDDS_DSI regulator\n");692		return PTR_ERR(vdds_dsi);693	}694 695	dpi->vdds_dsi_reg = vdds_dsi;696 697	return 0;698}699 700int dpi_init_port(struct dss_device *dss, struct platform_device *pdev,701		  struct device_node *port, enum dss_model dss_model)702{703	struct dpi_data *dpi;704	struct device_node *ep;705	u32 datalines;706	int r;707 708	dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);709	if (!dpi)710		return -ENOMEM;711 712	ep = of_get_next_child(port, NULL);713	if (!ep)714		return 0;715 716	r = of_property_read_u32(ep, "data-lines", &datalines);717	of_node_put(ep);718	if (r) {719		DSSERR("failed to parse datalines\n");720		return r;721	}722 723	dpi->data_lines = datalines;724 725	dpi->pdev = pdev;726	dpi->dss_model = dss_model;727	dpi->dss = dss;728	port->data = dpi;729 730	r = dpi_init_regulator(dpi);731	if (r)732		return r;733 734	return dpi_init_output_port(dpi, port);735}736 737void dpi_uninit_port(struct device_node *port)738{739	struct dpi_data *dpi = port->data;740 741	if (!dpi)742		return;743 744	dpi_uninit_output_port(port);745}746