brintos

brintos / linux-shallow public Read only

0
0
Text · 8.7 KiB · 91eaae3 Raw
398 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 7#define DSS_SUBSYS_NAME "SDI"8 9#include <linux/delay.h>10#include <linux/err.h>11#include <linux/export.h>12#include <linux/kernel.h>13#include <linux/of.h>14#include <linux/platform_device.h>15#include <linux/regulator/consumer.h>16#include <linux/string.h>17 18#include <drm/drm_bridge.h>19 20#include "dss.h"21#include "omapdss.h"22 23struct sdi_device {24	struct platform_device *pdev;25	struct dss_device *dss;26 27	bool update_enabled;28	struct regulator *vdds_sdi_reg;29 30	struct dss_lcd_mgr_config mgr_config;31	unsigned long pixelclock;32	int datapairs;33 34	struct omap_dss_device output;35	struct drm_bridge bridge;36};37 38#define drm_bridge_to_sdi(bridge) \39	container_of(bridge, struct sdi_device, bridge)40 41struct sdi_clk_calc_ctx {42	struct sdi_device *sdi;43	unsigned long pck_min, pck_max;44 45	unsigned long fck;46	struct dispc_clock_info dispc_cinfo;47};48 49static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,50		unsigned long pck, void *data)51{52	struct sdi_clk_calc_ctx *ctx = data;53 54	ctx->dispc_cinfo.lck_div = lckd;55	ctx->dispc_cinfo.pck_div = pckd;56	ctx->dispc_cinfo.lck = lck;57	ctx->dispc_cinfo.pck = pck;58 59	return true;60}61 62static bool dpi_calc_dss_cb(unsigned long fck, void *data)63{64	struct sdi_clk_calc_ctx *ctx = data;65 66	ctx->fck = fck;67 68	return dispc_div_calc(ctx->sdi->dss->dispc, fck,69			      ctx->pck_min, ctx->pck_max,70			      dpi_calc_dispc_cb, ctx);71}72 73static int sdi_calc_clock_div(struct sdi_device *sdi, unsigned long pclk,74			      unsigned long *fck,75			      struct dispc_clock_info *dispc_cinfo)76{77	int i;78	struct sdi_clk_calc_ctx ctx;79 80	/*81	 * DSS fclk gives us very few possibilities, so finding a good pixel82	 * clock may not be possible. We try multiple times to find the clock,83	 * each time widening the pixel clock range we look for, up to84	 * +/- 1MHz.85	 */86 87	for (i = 0; i < 10; ++i) {88		bool ok;89 90		memset(&ctx, 0, sizeof(ctx));91 92		ctx.sdi = sdi;93 94		if (pclk > 1000 * i * i * i)95			ctx.pck_min = max(pclk - 1000 * i * i * i, 0lu);96		else97			ctx.pck_min = 0;98		ctx.pck_max = pclk + 1000 * i * i * i;99 100		ok = dss_div_calc(sdi->dss, pclk, ctx.pck_min,101				  dpi_calc_dss_cb, &ctx);102		if (ok) {103			*fck = ctx.fck;104			*dispc_cinfo = ctx.dispc_cinfo;105			return 0;106		}107	}108 109	return -EINVAL;110}111 112static void sdi_config_lcd_manager(struct sdi_device *sdi)113{114	sdi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;115 116	sdi->mgr_config.stallmode = false;117	sdi->mgr_config.fifohandcheck = false;118 119	sdi->mgr_config.video_port_width = 24;120	sdi->mgr_config.lcden_sig_polarity = 1;121 122	dss_mgr_set_lcd_config(&sdi->output, &sdi->mgr_config);123}124 125/* -----------------------------------------------------------------------------126 * DRM Bridge Operations127 */128 129static int sdi_bridge_attach(struct drm_bridge *bridge,130			     enum drm_bridge_attach_flags flags)131{132	struct sdi_device *sdi = drm_bridge_to_sdi(bridge);133 134	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))135		return -EINVAL;136 137	return drm_bridge_attach(bridge->encoder, sdi->output.next_bridge,138				 bridge, flags);139}140 141static enum drm_mode_status142sdi_bridge_mode_valid(struct drm_bridge *bridge,143		      const struct drm_display_info *info,144		      const struct drm_display_mode *mode)145{146	struct sdi_device *sdi = drm_bridge_to_sdi(bridge);147	unsigned long pixelclock = mode->clock * 1000;148	struct dispc_clock_info dispc_cinfo;149	unsigned long fck;150	int ret;151 152	if (pixelclock == 0)153		return MODE_NOCLOCK;154 155	ret = sdi_calc_clock_div(sdi, pixelclock, &fck, &dispc_cinfo);156	if (ret < 0)157		return MODE_CLOCK_RANGE;158 159	return MODE_OK;160}161 162static bool sdi_bridge_mode_fixup(struct drm_bridge *bridge,163				  const struct drm_display_mode *mode,164				  struct drm_display_mode *adjusted_mode)165{166	struct sdi_device *sdi = drm_bridge_to_sdi(bridge);167	unsigned long pixelclock = mode->clock * 1000;168	struct dispc_clock_info dispc_cinfo;169	unsigned long fck;170	unsigned long pck;171	int ret;172 173	ret = sdi_calc_clock_div(sdi, pixelclock, &fck, &dispc_cinfo);174	if (ret < 0)175		return false;176 177	pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div;178 179	if (pck != pixelclock)180		dev_dbg(&sdi->pdev->dev,181			"pixel clock adjusted from %lu Hz to %lu Hz\n",182			pixelclock, pck);183 184	adjusted_mode->clock = pck / 1000;185 186	return true;187}188 189static void sdi_bridge_mode_set(struct drm_bridge *bridge,190				const struct drm_display_mode *mode,191				const struct drm_display_mode *adjusted_mode)192{193	struct sdi_device *sdi = drm_bridge_to_sdi(bridge);194 195	sdi->pixelclock = adjusted_mode->clock * 1000;196}197 198static void sdi_bridge_enable(struct drm_bridge *bridge)199{200	struct sdi_device *sdi = drm_bridge_to_sdi(bridge);201	struct dispc_clock_info dispc_cinfo;202	unsigned long fck;203	int r;204 205	r = regulator_enable(sdi->vdds_sdi_reg);206	if (r)207		return;208 209	r = dispc_runtime_get(sdi->dss->dispc);210	if (r)211		goto err_get_dispc;212 213	r = sdi_calc_clock_div(sdi, sdi->pixelclock, &fck, &dispc_cinfo);214	if (r)215		goto err_calc_clock_div;216 217	sdi->mgr_config.clock_info = dispc_cinfo;218 219	r = dss_set_fck_rate(sdi->dss, fck);220	if (r)221		goto err_set_dss_clock_div;222 223	sdi_config_lcd_manager(sdi);224 225	/*226	 * LCLK and PCLK divisors are located in shadow registers, and we227	 * normally write them to DISPC registers when enabling the output.228	 * However, SDI uses pck-free as source clock for its PLL, and pck-free229	 * is affected by the divisors. And as we need the PLL before enabling230	 * the output, we need to write the divisors early.231	 *232	 * It seems just writing to the DISPC register is enough, and we don't233	 * need to care about the shadow register mechanism for pck-free. The234	 * exact reason for this is unknown.235	 */236	dispc_mgr_set_clock_div(sdi->dss->dispc, sdi->output.dispc_channel,237				&sdi->mgr_config.clock_info);238 239	dss_sdi_init(sdi->dss, sdi->datapairs);240	r = dss_sdi_enable(sdi->dss);241	if (r)242		goto err_sdi_enable;243	mdelay(2);244 245	r = dss_mgr_enable(&sdi->output);246	if (r)247		goto err_mgr_enable;248 249	return;250 251err_mgr_enable:252	dss_sdi_disable(sdi->dss);253err_sdi_enable:254err_set_dss_clock_div:255err_calc_clock_div:256	dispc_runtime_put(sdi->dss->dispc);257err_get_dispc:258	regulator_disable(sdi->vdds_sdi_reg);259}260 261static void sdi_bridge_disable(struct drm_bridge *bridge)262{263	struct sdi_device *sdi = drm_bridge_to_sdi(bridge);264 265	dss_mgr_disable(&sdi->output);266 267	dss_sdi_disable(sdi->dss);268 269	dispc_runtime_put(sdi->dss->dispc);270 271	regulator_disable(sdi->vdds_sdi_reg);272}273 274static const struct drm_bridge_funcs sdi_bridge_funcs = {275	.attach = sdi_bridge_attach,276	.mode_valid = sdi_bridge_mode_valid,277	.mode_fixup = sdi_bridge_mode_fixup,278	.mode_set = sdi_bridge_mode_set,279	.enable = sdi_bridge_enable,280	.disable = sdi_bridge_disable,281};282 283static void sdi_bridge_init(struct sdi_device *sdi)284{285	sdi->bridge.funcs = &sdi_bridge_funcs;286	sdi->bridge.of_node = sdi->pdev->dev.of_node;287	sdi->bridge.type = DRM_MODE_CONNECTOR_LVDS;288 289	drm_bridge_add(&sdi->bridge);290}291 292static void sdi_bridge_cleanup(struct sdi_device *sdi)293{294	drm_bridge_remove(&sdi->bridge);295}296 297/* -----------------------------------------------------------------------------298 * Initialisation and Cleanup299 */300 301static int sdi_init_output(struct sdi_device *sdi)302{303	struct omap_dss_device *out = &sdi->output;304	int r;305 306	sdi_bridge_init(sdi);307 308	out->dev = &sdi->pdev->dev;309	out->id = OMAP_DSS_OUTPUT_SDI;310	out->type = OMAP_DISPLAY_TYPE_SDI;311	out->name = "sdi.0";312	out->dispc_channel = OMAP_DSS_CHANNEL_LCD;313	/* We have SDI only on OMAP3, where it's on port 1 */314	out->of_port = 1;315	out->bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE	/* 15.5.9.1.2 */316		       | DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE;317 318	r = omapdss_device_init_output(out, &sdi->bridge);319	if (r < 0) {320		sdi_bridge_cleanup(sdi);321		return r;322	}323 324	omapdss_device_register(out);325 326	return 0;327}328 329static void sdi_uninit_output(struct sdi_device *sdi)330{331	omapdss_device_unregister(&sdi->output);332	omapdss_device_cleanup_output(&sdi->output);333 334	sdi_bridge_cleanup(sdi);335}336 337int sdi_init_port(struct dss_device *dss, struct platform_device *pdev,338		  struct device_node *port)339{340	struct sdi_device *sdi;341	struct device_node *ep;342	u32 datapairs;343	int r;344 345	sdi = kzalloc(sizeof(*sdi), GFP_KERNEL);346	if (!sdi)347		return -ENOMEM;348 349	ep = of_get_next_child(port, NULL);350	if (!ep) {351		r = 0;352		goto err_free;353	}354 355	r = of_property_read_u32(ep, "datapairs", &datapairs);356	of_node_put(ep);357	if (r) {358		DSSERR("failed to parse datapairs\n");359		goto err_free;360	}361 362	sdi->datapairs = datapairs;363	sdi->dss = dss;364 365	sdi->pdev = pdev;366	port->data = sdi;367 368	sdi->vdds_sdi_reg = devm_regulator_get(&pdev->dev, "vdds_sdi");369	if (IS_ERR(sdi->vdds_sdi_reg)) {370		r = PTR_ERR(sdi->vdds_sdi_reg);371		if (r != -EPROBE_DEFER)372			DSSERR("can't get VDDS_SDI regulator\n");373		goto err_free;374	}375 376	r = sdi_init_output(sdi);377	if (r)378		goto err_free;379 380	return 0;381 382err_free:383	kfree(sdi);384 385	return r;386}387 388void sdi_uninit_port(struct device_node *port)389{390	struct sdi_device *sdi = port->data;391 392	if (!sdi)393		return;394 395	sdi_uninit_output(sdi);396	kfree(sdi);397}398