162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2009 Nokia Corporation
462306a36Sopenharmony_ci * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Some code and ideas taken from drivers/video/omap/ driver
762306a36Sopenharmony_ci * by Imre Deak.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define DSS_SUBSYS_NAME "DSS"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/debugfs.h>
1362306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1462306a36Sopenharmony_ci#include <linux/kernel.h>
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/io.h>
1762306a36Sopenharmony_ci#include <linux/export.h>
1862306a36Sopenharmony_ci#include <linux/err.h>
1962306a36Sopenharmony_ci#include <linux/delay.h>
2062306a36Sopenharmony_ci#include <linux/seq_file.h>
2162306a36Sopenharmony_ci#include <linux/clk.h>
2262306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h>
2362306a36Sopenharmony_ci#include <linux/platform_device.h>
2462306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2562306a36Sopenharmony_ci#include <linux/gfp.h>
2662306a36Sopenharmony_ci#include <linux/sizes.h>
2762306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
2862306a36Sopenharmony_ci#include <linux/regmap.h>
2962306a36Sopenharmony_ci#include <linux/of.h>
3062306a36Sopenharmony_ci#include <linux/of_device.h>
3162306a36Sopenharmony_ci#include <linux/of_graph.h>
3262306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
3362306a36Sopenharmony_ci#include <linux/suspend.h>
3462306a36Sopenharmony_ci#include <linux/component.h>
3562306a36Sopenharmony_ci#include <linux/sys_soc.h>
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#include "omapdss.h"
3862306a36Sopenharmony_ci#include "dss.h"
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistruct dss_reg {
4162306a36Sopenharmony_ci	u16 idx;
4262306a36Sopenharmony_ci};
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define DSS_REG(idx)			((const struct dss_reg) { idx })
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define DSS_REVISION			DSS_REG(0x0000)
4762306a36Sopenharmony_ci#define DSS_SYSCONFIG			DSS_REG(0x0010)
4862306a36Sopenharmony_ci#define DSS_SYSSTATUS			DSS_REG(0x0014)
4962306a36Sopenharmony_ci#define DSS_CONTROL			DSS_REG(0x0040)
5062306a36Sopenharmony_ci#define DSS_SDI_CONTROL			DSS_REG(0x0044)
5162306a36Sopenharmony_ci#define DSS_PLL_CONTROL			DSS_REG(0x0048)
5262306a36Sopenharmony_ci#define DSS_SDI_STATUS			DSS_REG(0x005C)
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#define REG_GET(dss, idx, start, end) \
5562306a36Sopenharmony_ci	FLD_GET(dss_read_reg(dss, idx), start, end)
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#define REG_FLD_MOD(dss, idx, val, start, end) \
5862306a36Sopenharmony_ci	dss_write_reg(dss, idx, \
5962306a36Sopenharmony_ci		      FLD_MOD(dss_read_reg(dss, idx), val, start, end))
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistruct dss_ops {
6262306a36Sopenharmony_ci	int (*dpi_select_source)(struct dss_device *dss, int port,
6362306a36Sopenharmony_ci				 enum omap_channel channel);
6462306a36Sopenharmony_ci	int (*select_lcd_source)(struct dss_device *dss,
6562306a36Sopenharmony_ci				 enum omap_channel channel,
6662306a36Sopenharmony_ci				 enum dss_clk_source clk_src);
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistruct dss_features {
7062306a36Sopenharmony_ci	enum dss_model model;
7162306a36Sopenharmony_ci	u8 fck_div_max;
7262306a36Sopenharmony_ci	unsigned int fck_freq_max;
7362306a36Sopenharmony_ci	u8 dss_fck_multiplier;
7462306a36Sopenharmony_ci	const char *parent_clk_name;
7562306a36Sopenharmony_ci	const enum omap_display_type *ports;
7662306a36Sopenharmony_ci	int num_ports;
7762306a36Sopenharmony_ci	const enum omap_dss_output_id *outputs;
7862306a36Sopenharmony_ci	const struct dss_ops *ops;
7962306a36Sopenharmony_ci	struct dss_reg_field dispc_clk_switch;
8062306a36Sopenharmony_ci	bool has_lcd_clk_src;
8162306a36Sopenharmony_ci};
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic const char * const dss_generic_clk_source_names[] = {
8462306a36Sopenharmony_ci	[DSS_CLK_SRC_FCK]	= "FCK",
8562306a36Sopenharmony_ci	[DSS_CLK_SRC_PLL1_1]	= "PLL1:1",
8662306a36Sopenharmony_ci	[DSS_CLK_SRC_PLL1_2]	= "PLL1:2",
8762306a36Sopenharmony_ci	[DSS_CLK_SRC_PLL1_3]	= "PLL1:3",
8862306a36Sopenharmony_ci	[DSS_CLK_SRC_PLL2_1]	= "PLL2:1",
8962306a36Sopenharmony_ci	[DSS_CLK_SRC_PLL2_2]	= "PLL2:2",
9062306a36Sopenharmony_ci	[DSS_CLK_SRC_PLL2_3]	= "PLL2:3",
9162306a36Sopenharmony_ci	[DSS_CLK_SRC_HDMI_PLL]	= "HDMI PLL",
9262306a36Sopenharmony_ci};
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic inline void dss_write_reg(struct dss_device *dss,
9562306a36Sopenharmony_ci				 const struct dss_reg idx, u32 val)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	__raw_writel(val, dss->base + idx.idx);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic inline u32 dss_read_reg(struct dss_device *dss, const struct dss_reg idx)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	return __raw_readl(dss->base + idx.idx);
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci#define SR(dss, reg) \
10662306a36Sopenharmony_ci	dss->ctx[(DSS_##reg).idx / sizeof(u32)] = dss_read_reg(dss, DSS_##reg)
10762306a36Sopenharmony_ci#define RR(dss, reg) \
10862306a36Sopenharmony_ci	dss_write_reg(dss, DSS_##reg, dss->ctx[(DSS_##reg).idx / sizeof(u32)])
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic void dss_save_context(struct dss_device *dss)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	DSSDBG("dss_save_context\n");
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	SR(dss, CONTROL);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	if (dss->feat->outputs[OMAP_DSS_CHANNEL_LCD] & OMAP_DSS_OUTPUT_SDI) {
11762306a36Sopenharmony_ci		SR(dss, SDI_CONTROL);
11862306a36Sopenharmony_ci		SR(dss, PLL_CONTROL);
11962306a36Sopenharmony_ci	}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	dss->ctx_valid = true;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	DSSDBG("context saved\n");
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic void dss_restore_context(struct dss_device *dss)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	DSSDBG("dss_restore_context\n");
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	if (!dss->ctx_valid)
13162306a36Sopenharmony_ci		return;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	RR(dss, CONTROL);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	if (dss->feat->outputs[OMAP_DSS_CHANNEL_LCD] & OMAP_DSS_OUTPUT_SDI) {
13662306a36Sopenharmony_ci		RR(dss, SDI_CONTROL);
13762306a36Sopenharmony_ci		RR(dss, PLL_CONTROL);
13862306a36Sopenharmony_ci	}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	DSSDBG("context restored\n");
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci#undef SR
14462306a36Sopenharmony_ci#undef RR
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_civoid dss_ctrl_pll_enable(struct dss_pll *pll, bool enable)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	unsigned int shift;
14962306a36Sopenharmony_ci	unsigned int val;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	if (!pll->dss->syscon_pll_ctrl)
15262306a36Sopenharmony_ci		return;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	val = !enable;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	switch (pll->id) {
15762306a36Sopenharmony_ci	case DSS_PLL_VIDEO1:
15862306a36Sopenharmony_ci		shift = 0;
15962306a36Sopenharmony_ci		break;
16062306a36Sopenharmony_ci	case DSS_PLL_VIDEO2:
16162306a36Sopenharmony_ci		shift = 1;
16262306a36Sopenharmony_ci		break;
16362306a36Sopenharmony_ci	case DSS_PLL_HDMI:
16462306a36Sopenharmony_ci		shift = 2;
16562306a36Sopenharmony_ci		break;
16662306a36Sopenharmony_ci	default:
16762306a36Sopenharmony_ci		DSSERR("illegal DSS PLL ID %d\n", pll->id);
16862306a36Sopenharmony_ci		return;
16962306a36Sopenharmony_ci	}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	regmap_update_bits(pll->dss->syscon_pll_ctrl,
17262306a36Sopenharmony_ci			   pll->dss->syscon_pll_ctrl_offset,
17362306a36Sopenharmony_ci			   1 << shift, val << shift);
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic int dss_ctrl_pll_set_control_mux(struct dss_device *dss,
17762306a36Sopenharmony_ci					enum dss_clk_source clk_src,
17862306a36Sopenharmony_ci					enum omap_channel channel)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	unsigned int shift, val;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	if (!dss->syscon_pll_ctrl)
18362306a36Sopenharmony_ci		return -EINVAL;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	switch (channel) {
18662306a36Sopenharmony_ci	case OMAP_DSS_CHANNEL_LCD:
18762306a36Sopenharmony_ci		shift = 3;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci		switch (clk_src) {
19062306a36Sopenharmony_ci		case DSS_CLK_SRC_PLL1_1:
19162306a36Sopenharmony_ci			val = 0; break;
19262306a36Sopenharmony_ci		case DSS_CLK_SRC_HDMI_PLL:
19362306a36Sopenharmony_ci			val = 1; break;
19462306a36Sopenharmony_ci		default:
19562306a36Sopenharmony_ci			DSSERR("error in PLL mux config for LCD\n");
19662306a36Sopenharmony_ci			return -EINVAL;
19762306a36Sopenharmony_ci		}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci		break;
20062306a36Sopenharmony_ci	case OMAP_DSS_CHANNEL_LCD2:
20162306a36Sopenharmony_ci		shift = 5;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci		switch (clk_src) {
20462306a36Sopenharmony_ci		case DSS_CLK_SRC_PLL1_3:
20562306a36Sopenharmony_ci			val = 0; break;
20662306a36Sopenharmony_ci		case DSS_CLK_SRC_PLL2_3:
20762306a36Sopenharmony_ci			val = 1; break;
20862306a36Sopenharmony_ci		case DSS_CLK_SRC_HDMI_PLL:
20962306a36Sopenharmony_ci			val = 2; break;
21062306a36Sopenharmony_ci		default:
21162306a36Sopenharmony_ci			DSSERR("error in PLL mux config for LCD2\n");
21262306a36Sopenharmony_ci			return -EINVAL;
21362306a36Sopenharmony_ci		}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci		break;
21662306a36Sopenharmony_ci	case OMAP_DSS_CHANNEL_LCD3:
21762306a36Sopenharmony_ci		shift = 7;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci		switch (clk_src) {
22062306a36Sopenharmony_ci		case DSS_CLK_SRC_PLL2_1:
22162306a36Sopenharmony_ci			val = 0; break;
22262306a36Sopenharmony_ci		case DSS_CLK_SRC_PLL1_3:
22362306a36Sopenharmony_ci			val = 1; break;
22462306a36Sopenharmony_ci		case DSS_CLK_SRC_HDMI_PLL:
22562306a36Sopenharmony_ci			val = 2; break;
22662306a36Sopenharmony_ci		default:
22762306a36Sopenharmony_ci			DSSERR("error in PLL mux config for LCD3\n");
22862306a36Sopenharmony_ci			return -EINVAL;
22962306a36Sopenharmony_ci		}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci		break;
23262306a36Sopenharmony_ci	default:
23362306a36Sopenharmony_ci		DSSERR("error in PLL mux config\n");
23462306a36Sopenharmony_ci		return -EINVAL;
23562306a36Sopenharmony_ci	}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	regmap_update_bits(dss->syscon_pll_ctrl, dss->syscon_pll_ctrl_offset,
23862306a36Sopenharmony_ci		0x3 << shift, val << shift);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	return 0;
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_civoid dss_sdi_init(struct dss_device *dss, int datapairs)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	u32 l;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	BUG_ON(datapairs > 3 || datapairs < 1);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	l = dss_read_reg(dss, DSS_SDI_CONTROL);
25062306a36Sopenharmony_ci	l = FLD_MOD(l, 0xf, 19, 15);		/* SDI_PDIV */
25162306a36Sopenharmony_ci	l = FLD_MOD(l, datapairs-1, 3, 2);	/* SDI_PRSEL */
25262306a36Sopenharmony_ci	l = FLD_MOD(l, 2, 1, 0);		/* SDI_BWSEL */
25362306a36Sopenharmony_ci	dss_write_reg(dss, DSS_SDI_CONTROL, l);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	l = dss_read_reg(dss, DSS_PLL_CONTROL);
25662306a36Sopenharmony_ci	l = FLD_MOD(l, 0x7, 25, 22);	/* SDI_PLL_FREQSEL */
25762306a36Sopenharmony_ci	l = FLD_MOD(l, 0xb, 16, 11);	/* SDI_PLL_REGN */
25862306a36Sopenharmony_ci	l = FLD_MOD(l, 0xb4, 10, 1);	/* SDI_PLL_REGM */
25962306a36Sopenharmony_ci	dss_write_reg(dss, DSS_PLL_CONTROL, l);
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ciint dss_sdi_enable(struct dss_device *dss)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	unsigned long timeout;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	dispc_pck_free_enable(dss->dispc, 1);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	/* Reset SDI PLL */
26962306a36Sopenharmony_ci	REG_FLD_MOD(dss, DSS_PLL_CONTROL, 1, 18, 18); /* SDI_PLL_SYSRESET */
27062306a36Sopenharmony_ci	udelay(1);	/* wait 2x PCLK */
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	/* Lock SDI PLL */
27362306a36Sopenharmony_ci	REG_FLD_MOD(dss, DSS_PLL_CONTROL, 1, 28, 28); /* SDI_PLL_GOBIT */
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	/* Waiting for PLL lock request to complete */
27662306a36Sopenharmony_ci	timeout = jiffies + msecs_to_jiffies(500);
27762306a36Sopenharmony_ci	while (dss_read_reg(dss, DSS_SDI_STATUS) & (1 << 6)) {
27862306a36Sopenharmony_ci		if (time_after_eq(jiffies, timeout)) {
27962306a36Sopenharmony_ci			DSSERR("PLL lock request timed out\n");
28062306a36Sopenharmony_ci			goto err1;
28162306a36Sopenharmony_ci		}
28262306a36Sopenharmony_ci	}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	/* Clearing PLL_GO bit */
28562306a36Sopenharmony_ci	REG_FLD_MOD(dss, DSS_PLL_CONTROL, 0, 28, 28);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	/* Waiting for PLL to lock */
28862306a36Sopenharmony_ci	timeout = jiffies + msecs_to_jiffies(500);
28962306a36Sopenharmony_ci	while (!(dss_read_reg(dss, DSS_SDI_STATUS) & (1 << 5))) {
29062306a36Sopenharmony_ci		if (time_after_eq(jiffies, timeout)) {
29162306a36Sopenharmony_ci			DSSERR("PLL lock timed out\n");
29262306a36Sopenharmony_ci			goto err1;
29362306a36Sopenharmony_ci		}
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	dispc_lcd_enable_signal(dss->dispc, 1);
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	/* Waiting for SDI reset to complete */
29962306a36Sopenharmony_ci	timeout = jiffies + msecs_to_jiffies(500);
30062306a36Sopenharmony_ci	while (!(dss_read_reg(dss, DSS_SDI_STATUS) & (1 << 2))) {
30162306a36Sopenharmony_ci		if (time_after_eq(jiffies, timeout)) {
30262306a36Sopenharmony_ci			DSSERR("SDI reset timed out\n");
30362306a36Sopenharmony_ci			goto err2;
30462306a36Sopenharmony_ci		}
30562306a36Sopenharmony_ci	}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	return 0;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci err2:
31062306a36Sopenharmony_ci	dispc_lcd_enable_signal(dss->dispc, 0);
31162306a36Sopenharmony_ci err1:
31262306a36Sopenharmony_ci	/* Reset SDI PLL */
31362306a36Sopenharmony_ci	REG_FLD_MOD(dss, DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	dispc_pck_free_enable(dss->dispc, 0);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	return -ETIMEDOUT;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_civoid dss_sdi_disable(struct dss_device *dss)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	dispc_lcd_enable_signal(dss->dispc, 0);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	dispc_pck_free_enable(dss->dispc, 0);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	/* Reset SDI PLL */
32762306a36Sopenharmony_ci	REG_FLD_MOD(dss, DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ciconst char *dss_get_clk_source_name(enum dss_clk_source clk_src)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	return dss_generic_clk_source_names[clk_src];
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic void dss_dump_clocks(struct dss_device *dss, struct seq_file *s)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	const char *fclk_name;
33862306a36Sopenharmony_ci	unsigned long fclk_rate;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	if (dss_runtime_get(dss))
34162306a36Sopenharmony_ci		return;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	seq_printf(s, "- DSS -\n");
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	fclk_name = dss_get_clk_source_name(DSS_CLK_SRC_FCK);
34662306a36Sopenharmony_ci	fclk_rate = clk_get_rate(dss->dss_clk);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	seq_printf(s, "%s = %lu\n",
34962306a36Sopenharmony_ci			fclk_name,
35062306a36Sopenharmony_ci			fclk_rate);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	dss_runtime_put(dss);
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_cistatic int dss_dump_regs(struct seq_file *s, void *p)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	struct dss_device *dss = s->private;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci#define DUMPREG(dss, r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(dss, r))
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	if (dss_runtime_get(dss))
36262306a36Sopenharmony_ci		return 0;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	DUMPREG(dss, DSS_REVISION);
36562306a36Sopenharmony_ci	DUMPREG(dss, DSS_SYSCONFIG);
36662306a36Sopenharmony_ci	DUMPREG(dss, DSS_SYSSTATUS);
36762306a36Sopenharmony_ci	DUMPREG(dss, DSS_CONTROL);
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	if (dss->feat->outputs[OMAP_DSS_CHANNEL_LCD] & OMAP_DSS_OUTPUT_SDI) {
37062306a36Sopenharmony_ci		DUMPREG(dss, DSS_SDI_CONTROL);
37162306a36Sopenharmony_ci		DUMPREG(dss, DSS_PLL_CONTROL);
37262306a36Sopenharmony_ci		DUMPREG(dss, DSS_SDI_STATUS);
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	dss_runtime_put(dss);
37662306a36Sopenharmony_ci#undef DUMPREG
37762306a36Sopenharmony_ci	return 0;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic int dss_debug_dump_clocks(struct seq_file *s, void *p)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	struct dss_device *dss = s->private;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	dss_dump_clocks(dss, s);
38562306a36Sopenharmony_ci	dispc_dump_clocks(dss->dispc, s);
38662306a36Sopenharmony_ci	return 0;
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_cistatic int dss_get_channel_index(enum omap_channel channel)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	switch (channel) {
39262306a36Sopenharmony_ci	case OMAP_DSS_CHANNEL_LCD:
39362306a36Sopenharmony_ci		return 0;
39462306a36Sopenharmony_ci	case OMAP_DSS_CHANNEL_LCD2:
39562306a36Sopenharmony_ci		return 1;
39662306a36Sopenharmony_ci	case OMAP_DSS_CHANNEL_LCD3:
39762306a36Sopenharmony_ci		return 2;
39862306a36Sopenharmony_ci	default:
39962306a36Sopenharmony_ci		WARN_ON(1);
40062306a36Sopenharmony_ci		return 0;
40162306a36Sopenharmony_ci	}
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cistatic void dss_select_dispc_clk_source(struct dss_device *dss,
40562306a36Sopenharmony_ci					enum dss_clk_source clk_src)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	int b;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	/*
41062306a36Sopenharmony_ci	 * We always use PRCM clock as the DISPC func clock, except on DSS3,
41162306a36Sopenharmony_ci	 * where we don't have separate DISPC and LCD clock sources.
41262306a36Sopenharmony_ci	 */
41362306a36Sopenharmony_ci	if (WARN_ON(dss->feat->has_lcd_clk_src && clk_src != DSS_CLK_SRC_FCK))
41462306a36Sopenharmony_ci		return;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	switch (clk_src) {
41762306a36Sopenharmony_ci	case DSS_CLK_SRC_FCK:
41862306a36Sopenharmony_ci		b = 0;
41962306a36Sopenharmony_ci		break;
42062306a36Sopenharmony_ci	case DSS_CLK_SRC_PLL1_1:
42162306a36Sopenharmony_ci		b = 1;
42262306a36Sopenharmony_ci		break;
42362306a36Sopenharmony_ci	case DSS_CLK_SRC_PLL2_1:
42462306a36Sopenharmony_ci		b = 2;
42562306a36Sopenharmony_ci		break;
42662306a36Sopenharmony_ci	default:
42762306a36Sopenharmony_ci		BUG();
42862306a36Sopenharmony_ci		return;
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	REG_FLD_MOD(dss, DSS_CONTROL, b,		/* DISPC_CLK_SWITCH */
43262306a36Sopenharmony_ci		    dss->feat->dispc_clk_switch.start,
43362306a36Sopenharmony_ci		    dss->feat->dispc_clk_switch.end);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	dss->dispc_clk_source = clk_src;
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_civoid dss_select_dsi_clk_source(struct dss_device *dss, int dsi_module,
43962306a36Sopenharmony_ci			       enum dss_clk_source clk_src)
44062306a36Sopenharmony_ci{
44162306a36Sopenharmony_ci	int b, pos;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	switch (clk_src) {
44462306a36Sopenharmony_ci	case DSS_CLK_SRC_FCK:
44562306a36Sopenharmony_ci		b = 0;
44662306a36Sopenharmony_ci		break;
44762306a36Sopenharmony_ci	case DSS_CLK_SRC_PLL1_2:
44862306a36Sopenharmony_ci		BUG_ON(dsi_module != 0);
44962306a36Sopenharmony_ci		b = 1;
45062306a36Sopenharmony_ci		break;
45162306a36Sopenharmony_ci	case DSS_CLK_SRC_PLL2_2:
45262306a36Sopenharmony_ci		BUG_ON(dsi_module != 1);
45362306a36Sopenharmony_ci		b = 1;
45462306a36Sopenharmony_ci		break;
45562306a36Sopenharmony_ci	default:
45662306a36Sopenharmony_ci		BUG();
45762306a36Sopenharmony_ci		return;
45862306a36Sopenharmony_ci	}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	pos = dsi_module == 0 ? 1 : 10;
46162306a36Sopenharmony_ci	REG_FLD_MOD(dss, DSS_CONTROL, b, pos, pos);	/* DSIx_CLK_SWITCH */
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	dss->dsi_clk_source[dsi_module] = clk_src;
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic int dss_lcd_clk_mux_dra7(struct dss_device *dss,
46762306a36Sopenharmony_ci				enum omap_channel channel,
46862306a36Sopenharmony_ci				enum dss_clk_source clk_src)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	const u8 ctrl_bits[] = {
47162306a36Sopenharmony_ci		[OMAP_DSS_CHANNEL_LCD] = 0,
47262306a36Sopenharmony_ci		[OMAP_DSS_CHANNEL_LCD2] = 12,
47362306a36Sopenharmony_ci		[OMAP_DSS_CHANNEL_LCD3] = 19,
47462306a36Sopenharmony_ci	};
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	u8 ctrl_bit = ctrl_bits[channel];
47762306a36Sopenharmony_ci	int r;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	if (clk_src == DSS_CLK_SRC_FCK) {
48062306a36Sopenharmony_ci		/* LCDx_CLK_SWITCH */
48162306a36Sopenharmony_ci		REG_FLD_MOD(dss, DSS_CONTROL, 0, ctrl_bit, ctrl_bit);
48262306a36Sopenharmony_ci		return -EINVAL;
48362306a36Sopenharmony_ci	}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	r = dss_ctrl_pll_set_control_mux(dss, clk_src, channel);
48662306a36Sopenharmony_ci	if (r)
48762306a36Sopenharmony_ci		return r;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	REG_FLD_MOD(dss, DSS_CONTROL, 1, ctrl_bit, ctrl_bit);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	return 0;
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_cistatic int dss_lcd_clk_mux_omap5(struct dss_device *dss,
49562306a36Sopenharmony_ci				 enum omap_channel channel,
49662306a36Sopenharmony_ci				 enum dss_clk_source clk_src)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	const u8 ctrl_bits[] = {
49962306a36Sopenharmony_ci		[OMAP_DSS_CHANNEL_LCD] = 0,
50062306a36Sopenharmony_ci		[OMAP_DSS_CHANNEL_LCD2] = 12,
50162306a36Sopenharmony_ci		[OMAP_DSS_CHANNEL_LCD3] = 19,
50262306a36Sopenharmony_ci	};
50362306a36Sopenharmony_ci	const enum dss_clk_source allowed_plls[] = {
50462306a36Sopenharmony_ci		[OMAP_DSS_CHANNEL_LCD] = DSS_CLK_SRC_PLL1_1,
50562306a36Sopenharmony_ci		[OMAP_DSS_CHANNEL_LCD2] = DSS_CLK_SRC_FCK,
50662306a36Sopenharmony_ci		[OMAP_DSS_CHANNEL_LCD3] = DSS_CLK_SRC_PLL2_1,
50762306a36Sopenharmony_ci	};
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	u8 ctrl_bit = ctrl_bits[channel];
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	if (clk_src == DSS_CLK_SRC_FCK) {
51262306a36Sopenharmony_ci		/* LCDx_CLK_SWITCH */
51362306a36Sopenharmony_ci		REG_FLD_MOD(dss, DSS_CONTROL, 0, ctrl_bit, ctrl_bit);
51462306a36Sopenharmony_ci		return -EINVAL;
51562306a36Sopenharmony_ci	}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	if (WARN_ON(allowed_plls[channel] != clk_src))
51862306a36Sopenharmony_ci		return -EINVAL;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	REG_FLD_MOD(dss, DSS_CONTROL, 1, ctrl_bit, ctrl_bit);
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	return 0;
52362306a36Sopenharmony_ci}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_cistatic int dss_lcd_clk_mux_omap4(struct dss_device *dss,
52662306a36Sopenharmony_ci				 enum omap_channel channel,
52762306a36Sopenharmony_ci				 enum dss_clk_source clk_src)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	const u8 ctrl_bits[] = {
53062306a36Sopenharmony_ci		[OMAP_DSS_CHANNEL_LCD] = 0,
53162306a36Sopenharmony_ci		[OMAP_DSS_CHANNEL_LCD2] = 12,
53262306a36Sopenharmony_ci	};
53362306a36Sopenharmony_ci	const enum dss_clk_source allowed_plls[] = {
53462306a36Sopenharmony_ci		[OMAP_DSS_CHANNEL_LCD] = DSS_CLK_SRC_PLL1_1,
53562306a36Sopenharmony_ci		[OMAP_DSS_CHANNEL_LCD2] = DSS_CLK_SRC_PLL2_1,
53662306a36Sopenharmony_ci	};
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	u8 ctrl_bit = ctrl_bits[channel];
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	if (clk_src == DSS_CLK_SRC_FCK) {
54162306a36Sopenharmony_ci		/* LCDx_CLK_SWITCH */
54262306a36Sopenharmony_ci		REG_FLD_MOD(dss, DSS_CONTROL, 0, ctrl_bit, ctrl_bit);
54362306a36Sopenharmony_ci		return 0;
54462306a36Sopenharmony_ci	}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	if (WARN_ON(allowed_plls[channel] != clk_src))
54762306a36Sopenharmony_ci		return -EINVAL;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	REG_FLD_MOD(dss, DSS_CONTROL, 1, ctrl_bit, ctrl_bit);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	return 0;
55262306a36Sopenharmony_ci}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_civoid dss_select_lcd_clk_source(struct dss_device *dss,
55562306a36Sopenharmony_ci			       enum omap_channel channel,
55662306a36Sopenharmony_ci			       enum dss_clk_source clk_src)
55762306a36Sopenharmony_ci{
55862306a36Sopenharmony_ci	int idx = dss_get_channel_index(channel);
55962306a36Sopenharmony_ci	int r;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	if (!dss->feat->has_lcd_clk_src) {
56262306a36Sopenharmony_ci		dss_select_dispc_clk_source(dss, clk_src);
56362306a36Sopenharmony_ci		dss->lcd_clk_source[idx] = clk_src;
56462306a36Sopenharmony_ci		return;
56562306a36Sopenharmony_ci	}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	r = dss->feat->ops->select_lcd_source(dss, channel, clk_src);
56862306a36Sopenharmony_ci	if (r)
56962306a36Sopenharmony_ci		return;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	dss->lcd_clk_source[idx] = clk_src;
57262306a36Sopenharmony_ci}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_cienum dss_clk_source dss_get_dispc_clk_source(struct dss_device *dss)
57562306a36Sopenharmony_ci{
57662306a36Sopenharmony_ci	return dss->dispc_clk_source;
57762306a36Sopenharmony_ci}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_cienum dss_clk_source dss_get_dsi_clk_source(struct dss_device *dss,
58062306a36Sopenharmony_ci					   int dsi_module)
58162306a36Sopenharmony_ci{
58262306a36Sopenharmony_ci	return dss->dsi_clk_source[dsi_module];
58362306a36Sopenharmony_ci}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_cienum dss_clk_source dss_get_lcd_clk_source(struct dss_device *dss,
58662306a36Sopenharmony_ci					   enum omap_channel channel)
58762306a36Sopenharmony_ci{
58862306a36Sopenharmony_ci	if (dss->feat->has_lcd_clk_src) {
58962306a36Sopenharmony_ci		int idx = dss_get_channel_index(channel);
59062306a36Sopenharmony_ci		return dss->lcd_clk_source[idx];
59162306a36Sopenharmony_ci	} else {
59262306a36Sopenharmony_ci		/* LCD_CLK source is the same as DISPC_FCLK source for
59362306a36Sopenharmony_ci		 * OMAP2 and OMAP3 */
59462306a36Sopenharmony_ci		return dss->dispc_clk_source;
59562306a36Sopenharmony_ci	}
59662306a36Sopenharmony_ci}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cibool dss_div_calc(struct dss_device *dss, unsigned long pck,
59962306a36Sopenharmony_ci		  unsigned long fck_min, dss_div_calc_func func, void *data)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	int fckd, fckd_start, fckd_stop;
60262306a36Sopenharmony_ci	unsigned long fck;
60362306a36Sopenharmony_ci	unsigned long fck_hw_max;
60462306a36Sopenharmony_ci	unsigned long fckd_hw_max;
60562306a36Sopenharmony_ci	unsigned long prate;
60662306a36Sopenharmony_ci	unsigned int m;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	fck_hw_max = dss->feat->fck_freq_max;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	if (dss->parent_clk == NULL) {
61162306a36Sopenharmony_ci		unsigned int pckd;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci		pckd = fck_hw_max / pck;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci		fck = pck * pckd;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci		fck = clk_round_rate(dss->dss_clk, fck);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci		return func(fck, data);
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	fckd_hw_max = dss->feat->fck_div_max;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	m = dss->feat->dss_fck_multiplier;
62562306a36Sopenharmony_ci	prate = clk_get_rate(dss->parent_clk);
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	fck_min = fck_min ? fck_min : 1;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	fckd_start = min(prate * m / fck_min, fckd_hw_max);
63062306a36Sopenharmony_ci	fckd_stop = max(DIV_ROUND_UP(prate * m, fck_hw_max), 1ul);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	for (fckd = fckd_start; fckd >= fckd_stop; --fckd) {
63362306a36Sopenharmony_ci		fck = DIV_ROUND_UP(prate, fckd) * m;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci		if (func(fck, data))
63662306a36Sopenharmony_ci			return true;
63762306a36Sopenharmony_ci	}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	return false;
64062306a36Sopenharmony_ci}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ciint dss_set_fck_rate(struct dss_device *dss, unsigned long rate)
64362306a36Sopenharmony_ci{
64462306a36Sopenharmony_ci	int r;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	DSSDBG("set fck to %lu\n", rate);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	r = clk_set_rate(dss->dss_clk, rate);
64962306a36Sopenharmony_ci	if (r)
65062306a36Sopenharmony_ci		return r;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	dss->dss_clk_rate = clk_get_rate(dss->dss_clk);
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	WARN_ONCE(dss->dss_clk_rate != rate, "clk rate mismatch: %lu != %lu",
65562306a36Sopenharmony_ci		  dss->dss_clk_rate, rate);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	return 0;
65862306a36Sopenharmony_ci}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ciunsigned long dss_get_dispc_clk_rate(struct dss_device *dss)
66162306a36Sopenharmony_ci{
66262306a36Sopenharmony_ci	return dss->dss_clk_rate;
66362306a36Sopenharmony_ci}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ciunsigned long dss_get_max_fck_rate(struct dss_device *dss)
66662306a36Sopenharmony_ci{
66762306a36Sopenharmony_ci	return dss->feat->fck_freq_max;
66862306a36Sopenharmony_ci}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cistatic int dss_setup_default_clock(struct dss_device *dss)
67162306a36Sopenharmony_ci{
67262306a36Sopenharmony_ci	unsigned long max_dss_fck, prate;
67362306a36Sopenharmony_ci	unsigned long fck;
67462306a36Sopenharmony_ci	unsigned int fck_div;
67562306a36Sopenharmony_ci	int r;
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	max_dss_fck = dss->feat->fck_freq_max;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	if (dss->parent_clk == NULL) {
68062306a36Sopenharmony_ci		fck = clk_round_rate(dss->dss_clk, max_dss_fck);
68162306a36Sopenharmony_ci	} else {
68262306a36Sopenharmony_ci		prate = clk_get_rate(dss->parent_clk);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci		fck_div = DIV_ROUND_UP(prate * dss->feat->dss_fck_multiplier,
68562306a36Sopenharmony_ci				max_dss_fck);
68662306a36Sopenharmony_ci		fck = DIV_ROUND_UP(prate, fck_div)
68762306a36Sopenharmony_ci		    * dss->feat->dss_fck_multiplier;
68862306a36Sopenharmony_ci	}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	r = dss_set_fck_rate(dss, fck);
69162306a36Sopenharmony_ci	if (r)
69262306a36Sopenharmony_ci		return r;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	return 0;
69562306a36Sopenharmony_ci}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_civoid dss_set_venc_output(struct dss_device *dss, enum omap_dss_venc_type type)
69862306a36Sopenharmony_ci{
69962306a36Sopenharmony_ci	int l = 0;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	if (type == OMAP_DSS_VENC_TYPE_COMPOSITE)
70262306a36Sopenharmony_ci		l = 0;
70362306a36Sopenharmony_ci	else if (type == OMAP_DSS_VENC_TYPE_SVIDEO)
70462306a36Sopenharmony_ci		l = 1;
70562306a36Sopenharmony_ci	else
70662306a36Sopenharmony_ci		BUG();
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	/* venc out selection. 0 = comp, 1 = svideo */
70962306a36Sopenharmony_ci	REG_FLD_MOD(dss, DSS_CONTROL, l, 6, 6);
71062306a36Sopenharmony_ci}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_civoid dss_set_dac_pwrdn_bgz(struct dss_device *dss, bool enable)
71362306a36Sopenharmony_ci{
71462306a36Sopenharmony_ci	/* DAC Power-Down Control */
71562306a36Sopenharmony_ci	REG_FLD_MOD(dss, DSS_CONTROL, enable, 5, 5);
71662306a36Sopenharmony_ci}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_civoid dss_select_hdmi_venc_clk_source(struct dss_device *dss,
71962306a36Sopenharmony_ci				     enum dss_hdmi_venc_clk_source_select src)
72062306a36Sopenharmony_ci{
72162306a36Sopenharmony_ci	enum omap_dss_output_id outputs;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	outputs = dss->feat->outputs[OMAP_DSS_CHANNEL_DIGIT];
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	/* Complain about invalid selections */
72662306a36Sopenharmony_ci	WARN_ON((src == DSS_VENC_TV_CLK) && !(outputs & OMAP_DSS_OUTPUT_VENC));
72762306a36Sopenharmony_ci	WARN_ON((src == DSS_HDMI_M_PCLK) && !(outputs & OMAP_DSS_OUTPUT_HDMI));
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	/* Select only if we have options */
73062306a36Sopenharmony_ci	if ((outputs & OMAP_DSS_OUTPUT_VENC) &&
73162306a36Sopenharmony_ci	    (outputs & OMAP_DSS_OUTPUT_HDMI))
73262306a36Sopenharmony_ci		/* VENC_HDMI_SWITCH */
73362306a36Sopenharmony_ci		REG_FLD_MOD(dss, DSS_CONTROL, src, 15, 15);
73462306a36Sopenharmony_ci}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_cistatic int dss_dpi_select_source_omap2_omap3(struct dss_device *dss, int port,
73762306a36Sopenharmony_ci					     enum omap_channel channel)
73862306a36Sopenharmony_ci{
73962306a36Sopenharmony_ci	if (channel != OMAP_DSS_CHANNEL_LCD)
74062306a36Sopenharmony_ci		return -EINVAL;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	return 0;
74362306a36Sopenharmony_ci}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_cistatic int dss_dpi_select_source_omap4(struct dss_device *dss, int port,
74662306a36Sopenharmony_ci				       enum omap_channel channel)
74762306a36Sopenharmony_ci{
74862306a36Sopenharmony_ci	int val;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	switch (channel) {
75162306a36Sopenharmony_ci	case OMAP_DSS_CHANNEL_LCD2:
75262306a36Sopenharmony_ci		val = 0;
75362306a36Sopenharmony_ci		break;
75462306a36Sopenharmony_ci	case OMAP_DSS_CHANNEL_DIGIT:
75562306a36Sopenharmony_ci		val = 1;
75662306a36Sopenharmony_ci		break;
75762306a36Sopenharmony_ci	default:
75862306a36Sopenharmony_ci		return -EINVAL;
75962306a36Sopenharmony_ci	}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	REG_FLD_MOD(dss, DSS_CONTROL, val, 17, 17);
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	return 0;
76462306a36Sopenharmony_ci}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_cistatic int dss_dpi_select_source_omap5(struct dss_device *dss, int port,
76762306a36Sopenharmony_ci				       enum omap_channel channel)
76862306a36Sopenharmony_ci{
76962306a36Sopenharmony_ci	int val;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	switch (channel) {
77262306a36Sopenharmony_ci	case OMAP_DSS_CHANNEL_LCD:
77362306a36Sopenharmony_ci		val = 1;
77462306a36Sopenharmony_ci		break;
77562306a36Sopenharmony_ci	case OMAP_DSS_CHANNEL_LCD2:
77662306a36Sopenharmony_ci		val = 2;
77762306a36Sopenharmony_ci		break;
77862306a36Sopenharmony_ci	case OMAP_DSS_CHANNEL_LCD3:
77962306a36Sopenharmony_ci		val = 3;
78062306a36Sopenharmony_ci		break;
78162306a36Sopenharmony_ci	case OMAP_DSS_CHANNEL_DIGIT:
78262306a36Sopenharmony_ci		val = 0;
78362306a36Sopenharmony_ci		break;
78462306a36Sopenharmony_ci	default:
78562306a36Sopenharmony_ci		return -EINVAL;
78662306a36Sopenharmony_ci	}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	REG_FLD_MOD(dss, DSS_CONTROL, val, 17, 16);
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	return 0;
79162306a36Sopenharmony_ci}
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_cistatic int dss_dpi_select_source_dra7xx(struct dss_device *dss, int port,
79462306a36Sopenharmony_ci					enum omap_channel channel)
79562306a36Sopenharmony_ci{
79662306a36Sopenharmony_ci	switch (port) {
79762306a36Sopenharmony_ci	case 0:
79862306a36Sopenharmony_ci		return dss_dpi_select_source_omap5(dss, port, channel);
79962306a36Sopenharmony_ci	case 1:
80062306a36Sopenharmony_ci		if (channel != OMAP_DSS_CHANNEL_LCD2)
80162306a36Sopenharmony_ci			return -EINVAL;
80262306a36Sopenharmony_ci		break;
80362306a36Sopenharmony_ci	case 2:
80462306a36Sopenharmony_ci		if (channel != OMAP_DSS_CHANNEL_LCD3)
80562306a36Sopenharmony_ci			return -EINVAL;
80662306a36Sopenharmony_ci		break;
80762306a36Sopenharmony_ci	default:
80862306a36Sopenharmony_ci		return -EINVAL;
80962306a36Sopenharmony_ci	}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	return 0;
81262306a36Sopenharmony_ci}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ciint dss_dpi_select_source(struct dss_device *dss, int port,
81562306a36Sopenharmony_ci			  enum omap_channel channel)
81662306a36Sopenharmony_ci{
81762306a36Sopenharmony_ci	return dss->feat->ops->dpi_select_source(dss, port, channel);
81862306a36Sopenharmony_ci}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_cistatic int dss_get_clocks(struct dss_device *dss)
82162306a36Sopenharmony_ci{
82262306a36Sopenharmony_ci	struct clk *clk;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	clk = devm_clk_get(&dss->pdev->dev, "fck");
82562306a36Sopenharmony_ci	if (IS_ERR(clk)) {
82662306a36Sopenharmony_ci		DSSERR("can't get clock fck\n");
82762306a36Sopenharmony_ci		return PTR_ERR(clk);
82862306a36Sopenharmony_ci	}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	dss->dss_clk = clk;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	if (dss->feat->parent_clk_name) {
83362306a36Sopenharmony_ci		clk = clk_get(NULL, dss->feat->parent_clk_name);
83462306a36Sopenharmony_ci		if (IS_ERR(clk)) {
83562306a36Sopenharmony_ci			DSSERR("Failed to get %s\n",
83662306a36Sopenharmony_ci			       dss->feat->parent_clk_name);
83762306a36Sopenharmony_ci			return PTR_ERR(clk);
83862306a36Sopenharmony_ci		}
83962306a36Sopenharmony_ci	} else {
84062306a36Sopenharmony_ci		clk = NULL;
84162306a36Sopenharmony_ci	}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	dss->parent_clk = clk;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	return 0;
84662306a36Sopenharmony_ci}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_cistatic void dss_put_clocks(struct dss_device *dss)
84962306a36Sopenharmony_ci{
85062306a36Sopenharmony_ci	if (dss->parent_clk)
85162306a36Sopenharmony_ci		clk_put(dss->parent_clk);
85262306a36Sopenharmony_ci}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ciint dss_runtime_get(struct dss_device *dss)
85562306a36Sopenharmony_ci{
85662306a36Sopenharmony_ci	int r;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	DSSDBG("dss_runtime_get\n");
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	r = pm_runtime_get_sync(&dss->pdev->dev);
86162306a36Sopenharmony_ci	if (WARN_ON(r < 0)) {
86262306a36Sopenharmony_ci		pm_runtime_put_noidle(&dss->pdev->dev);
86362306a36Sopenharmony_ci		return r;
86462306a36Sopenharmony_ci	}
86562306a36Sopenharmony_ci	return 0;
86662306a36Sopenharmony_ci}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_civoid dss_runtime_put(struct dss_device *dss)
86962306a36Sopenharmony_ci{
87062306a36Sopenharmony_ci	int r;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	DSSDBG("dss_runtime_put\n");
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	r = pm_runtime_put_sync(&dss->pdev->dev);
87562306a36Sopenharmony_ci	WARN_ON(r < 0 && r != -ENOSYS && r != -EBUSY);
87662306a36Sopenharmony_ci}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_cistruct dss_device *dss_get_device(struct device *dev)
87962306a36Sopenharmony_ci{
88062306a36Sopenharmony_ci	return dev_get_drvdata(dev);
88162306a36Sopenharmony_ci}
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci/* DEBUGFS */
88462306a36Sopenharmony_ci#if defined(CONFIG_OMAP2_DSS_DEBUGFS)
88562306a36Sopenharmony_cistatic int dss_initialize_debugfs(struct dss_device *dss)
88662306a36Sopenharmony_ci{
88762306a36Sopenharmony_ci	struct dentry *dir;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	dir = debugfs_create_dir("omapdss", NULL);
89062306a36Sopenharmony_ci	if (IS_ERR(dir))
89162306a36Sopenharmony_ci		return PTR_ERR(dir);
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	dss->debugfs.root = dir;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	return 0;
89662306a36Sopenharmony_ci}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_cistatic void dss_uninitialize_debugfs(struct dss_device *dss)
89962306a36Sopenharmony_ci{
90062306a36Sopenharmony_ci	debugfs_remove_recursive(dss->debugfs.root);
90162306a36Sopenharmony_ci}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_cistruct dss_debugfs_entry {
90462306a36Sopenharmony_ci	struct dentry *dentry;
90562306a36Sopenharmony_ci	int (*show_fn)(struct seq_file *s, void *data);
90662306a36Sopenharmony_ci	void *data;
90762306a36Sopenharmony_ci};
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_cistatic int dss_debug_open(struct inode *inode, struct file *file)
91062306a36Sopenharmony_ci{
91162306a36Sopenharmony_ci	struct dss_debugfs_entry *entry = inode->i_private;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	return single_open(file, entry->show_fn, entry->data);
91462306a36Sopenharmony_ci}
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_cistatic const struct file_operations dss_debug_fops = {
91762306a36Sopenharmony_ci	.open		= dss_debug_open,
91862306a36Sopenharmony_ci	.read		= seq_read,
91962306a36Sopenharmony_ci	.llseek		= seq_lseek,
92062306a36Sopenharmony_ci	.release	= single_release,
92162306a36Sopenharmony_ci};
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_cistruct dss_debugfs_entry *
92462306a36Sopenharmony_cidss_debugfs_create_file(struct dss_device *dss, const char *name,
92562306a36Sopenharmony_ci			int (*show_fn)(struct seq_file *s, void *data),
92662306a36Sopenharmony_ci			void *data)
92762306a36Sopenharmony_ci{
92862306a36Sopenharmony_ci	struct dss_debugfs_entry *entry;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
93162306a36Sopenharmony_ci	if (!entry)
93262306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	entry->show_fn = show_fn;
93562306a36Sopenharmony_ci	entry->data = data;
93662306a36Sopenharmony_ci	entry->dentry = debugfs_create_file(name, 0444, dss->debugfs.root,
93762306a36Sopenharmony_ci					    entry, &dss_debug_fops);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	return entry;
94062306a36Sopenharmony_ci}
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_civoid dss_debugfs_remove_file(struct dss_debugfs_entry *entry)
94362306a36Sopenharmony_ci{
94462306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(entry))
94562306a36Sopenharmony_ci		return;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	debugfs_remove(entry->dentry);
94862306a36Sopenharmony_ci	kfree(entry);
94962306a36Sopenharmony_ci}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci#else /* CONFIG_OMAP2_DSS_DEBUGFS */
95262306a36Sopenharmony_cistatic inline int dss_initialize_debugfs(struct dss_device *dss)
95362306a36Sopenharmony_ci{
95462306a36Sopenharmony_ci	return 0;
95562306a36Sopenharmony_ci}
95662306a36Sopenharmony_cistatic inline void dss_uninitialize_debugfs(struct dss_device *dss)
95762306a36Sopenharmony_ci{
95862306a36Sopenharmony_ci}
95962306a36Sopenharmony_ci#endif /* CONFIG_OMAP2_DSS_DEBUGFS */
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_cistatic const struct dss_ops dss_ops_omap2_omap3 = {
96262306a36Sopenharmony_ci	.dpi_select_source = &dss_dpi_select_source_omap2_omap3,
96362306a36Sopenharmony_ci};
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_cistatic const struct dss_ops dss_ops_omap4 = {
96662306a36Sopenharmony_ci	.dpi_select_source = &dss_dpi_select_source_omap4,
96762306a36Sopenharmony_ci	.select_lcd_source = &dss_lcd_clk_mux_omap4,
96862306a36Sopenharmony_ci};
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_cistatic const struct dss_ops dss_ops_omap5 = {
97162306a36Sopenharmony_ci	.dpi_select_source = &dss_dpi_select_source_omap5,
97262306a36Sopenharmony_ci	.select_lcd_source = &dss_lcd_clk_mux_omap5,
97362306a36Sopenharmony_ci};
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_cistatic const struct dss_ops dss_ops_dra7 = {
97662306a36Sopenharmony_ci	.dpi_select_source = &dss_dpi_select_source_dra7xx,
97762306a36Sopenharmony_ci	.select_lcd_source = &dss_lcd_clk_mux_dra7,
97862306a36Sopenharmony_ci};
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_cistatic const enum omap_display_type omap2plus_ports[] = {
98162306a36Sopenharmony_ci	OMAP_DISPLAY_TYPE_DPI,
98262306a36Sopenharmony_ci};
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_cistatic const enum omap_display_type omap34xx_ports[] = {
98562306a36Sopenharmony_ci	OMAP_DISPLAY_TYPE_DPI,
98662306a36Sopenharmony_ci	OMAP_DISPLAY_TYPE_SDI,
98762306a36Sopenharmony_ci};
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_cistatic const enum omap_display_type dra7xx_ports[] = {
99062306a36Sopenharmony_ci	OMAP_DISPLAY_TYPE_DPI,
99162306a36Sopenharmony_ci	OMAP_DISPLAY_TYPE_DPI,
99262306a36Sopenharmony_ci	OMAP_DISPLAY_TYPE_DPI,
99362306a36Sopenharmony_ci};
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_cistatic const enum omap_dss_output_id omap2_dss_supported_outputs[] = {
99662306a36Sopenharmony_ci	/* OMAP_DSS_CHANNEL_LCD */
99762306a36Sopenharmony_ci	OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI,
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	/* OMAP_DSS_CHANNEL_DIGIT */
100062306a36Sopenharmony_ci	OMAP_DSS_OUTPUT_VENC,
100162306a36Sopenharmony_ci};
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_cistatic const enum omap_dss_output_id omap3430_dss_supported_outputs[] = {
100462306a36Sopenharmony_ci	/* OMAP_DSS_CHANNEL_LCD */
100562306a36Sopenharmony_ci	OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
100662306a36Sopenharmony_ci	OMAP_DSS_OUTPUT_SDI | OMAP_DSS_OUTPUT_DSI1,
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	/* OMAP_DSS_CHANNEL_DIGIT */
100962306a36Sopenharmony_ci	OMAP_DSS_OUTPUT_VENC,
101062306a36Sopenharmony_ci};
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_cistatic const enum omap_dss_output_id omap3630_dss_supported_outputs[] = {
101362306a36Sopenharmony_ci	/* OMAP_DSS_CHANNEL_LCD */
101462306a36Sopenharmony_ci	OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
101562306a36Sopenharmony_ci	OMAP_DSS_OUTPUT_DSI1,
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	/* OMAP_DSS_CHANNEL_DIGIT */
101862306a36Sopenharmony_ci	OMAP_DSS_OUTPUT_VENC,
101962306a36Sopenharmony_ci};
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_cistatic const enum omap_dss_output_id am43xx_dss_supported_outputs[] = {
102262306a36Sopenharmony_ci	/* OMAP_DSS_CHANNEL_LCD */
102362306a36Sopenharmony_ci	OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI,
102462306a36Sopenharmony_ci};
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_cistatic const enum omap_dss_output_id omap4_dss_supported_outputs[] = {
102762306a36Sopenharmony_ci	/* OMAP_DSS_CHANNEL_LCD */
102862306a36Sopenharmony_ci	OMAP_DSS_OUTPUT_DBI | OMAP_DSS_OUTPUT_DSI1,
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	/* OMAP_DSS_CHANNEL_DIGIT */
103162306a36Sopenharmony_ci	OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI,
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	/* OMAP_DSS_CHANNEL_LCD2 */
103462306a36Sopenharmony_ci	OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
103562306a36Sopenharmony_ci	OMAP_DSS_OUTPUT_DSI2,
103662306a36Sopenharmony_ci};
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_cistatic const enum omap_dss_output_id omap5_dss_supported_outputs[] = {
103962306a36Sopenharmony_ci	/* OMAP_DSS_CHANNEL_LCD */
104062306a36Sopenharmony_ci	OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
104162306a36Sopenharmony_ci	OMAP_DSS_OUTPUT_DSI1 | OMAP_DSS_OUTPUT_DSI2,
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	/* OMAP_DSS_CHANNEL_DIGIT */
104462306a36Sopenharmony_ci	OMAP_DSS_OUTPUT_HDMI,
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	/* OMAP_DSS_CHANNEL_LCD2 */
104762306a36Sopenharmony_ci	OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
104862306a36Sopenharmony_ci	OMAP_DSS_OUTPUT_DSI1,
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	/* OMAP_DSS_CHANNEL_LCD3 */
105162306a36Sopenharmony_ci	OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
105262306a36Sopenharmony_ci	OMAP_DSS_OUTPUT_DSI2,
105362306a36Sopenharmony_ci};
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_cistatic const struct dss_features omap24xx_dss_feats = {
105662306a36Sopenharmony_ci	.model			=	DSS_MODEL_OMAP2,
105762306a36Sopenharmony_ci	/*
105862306a36Sopenharmony_ci	 * fck div max is really 16, but the divider range has gaps. The range
105962306a36Sopenharmony_ci	 * from 1 to 6 has no gaps, so let's use that as a max.
106062306a36Sopenharmony_ci	 */
106162306a36Sopenharmony_ci	.fck_div_max		=	6,
106262306a36Sopenharmony_ci	.fck_freq_max		=	133000000,
106362306a36Sopenharmony_ci	.dss_fck_multiplier	=	2,
106462306a36Sopenharmony_ci	.parent_clk_name	=	"core_ck",
106562306a36Sopenharmony_ci	.ports			=	omap2plus_ports,
106662306a36Sopenharmony_ci	.num_ports		=	ARRAY_SIZE(omap2plus_ports),
106762306a36Sopenharmony_ci	.outputs		=	omap2_dss_supported_outputs,
106862306a36Sopenharmony_ci	.ops			=	&dss_ops_omap2_omap3,
106962306a36Sopenharmony_ci	.dispc_clk_switch	=	{ 0, 0 },
107062306a36Sopenharmony_ci	.has_lcd_clk_src	=	false,
107162306a36Sopenharmony_ci};
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_cistatic const struct dss_features omap34xx_dss_feats = {
107462306a36Sopenharmony_ci	.model			=	DSS_MODEL_OMAP3,
107562306a36Sopenharmony_ci	.fck_div_max		=	16,
107662306a36Sopenharmony_ci	.fck_freq_max		=	173000000,
107762306a36Sopenharmony_ci	.dss_fck_multiplier	=	2,
107862306a36Sopenharmony_ci	.parent_clk_name	=	"dpll4_ck",
107962306a36Sopenharmony_ci	.ports			=	omap34xx_ports,
108062306a36Sopenharmony_ci	.outputs		=	omap3430_dss_supported_outputs,
108162306a36Sopenharmony_ci	.num_ports		=	ARRAY_SIZE(omap34xx_ports),
108262306a36Sopenharmony_ci	.ops			=	&dss_ops_omap2_omap3,
108362306a36Sopenharmony_ci	.dispc_clk_switch	=	{ 0, 0 },
108462306a36Sopenharmony_ci	.has_lcd_clk_src	=	false,
108562306a36Sopenharmony_ci};
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_cistatic const struct dss_features omap3630_dss_feats = {
108862306a36Sopenharmony_ci	.model			=	DSS_MODEL_OMAP3,
108962306a36Sopenharmony_ci	.fck_div_max		=	31,
109062306a36Sopenharmony_ci	.fck_freq_max		=	173000000,
109162306a36Sopenharmony_ci	.dss_fck_multiplier	=	1,
109262306a36Sopenharmony_ci	.parent_clk_name	=	"dpll4_ck",
109362306a36Sopenharmony_ci	.ports			=	omap2plus_ports,
109462306a36Sopenharmony_ci	.num_ports		=	ARRAY_SIZE(omap2plus_ports),
109562306a36Sopenharmony_ci	.outputs		=	omap3630_dss_supported_outputs,
109662306a36Sopenharmony_ci	.ops			=	&dss_ops_omap2_omap3,
109762306a36Sopenharmony_ci	.dispc_clk_switch	=	{ 0, 0 },
109862306a36Sopenharmony_ci	.has_lcd_clk_src	=	false,
109962306a36Sopenharmony_ci};
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_cistatic const struct dss_features omap44xx_dss_feats = {
110262306a36Sopenharmony_ci	.model			=	DSS_MODEL_OMAP4,
110362306a36Sopenharmony_ci	.fck_div_max		=	32,
110462306a36Sopenharmony_ci	.fck_freq_max		=	186000000,
110562306a36Sopenharmony_ci	.dss_fck_multiplier	=	1,
110662306a36Sopenharmony_ci	.parent_clk_name	=	"dpll_per_x2_ck",
110762306a36Sopenharmony_ci	.ports			=	omap2plus_ports,
110862306a36Sopenharmony_ci	.num_ports		=	ARRAY_SIZE(omap2plus_ports),
110962306a36Sopenharmony_ci	.outputs		=	omap4_dss_supported_outputs,
111062306a36Sopenharmony_ci	.ops			=	&dss_ops_omap4,
111162306a36Sopenharmony_ci	.dispc_clk_switch	=	{ 9, 8 },
111262306a36Sopenharmony_ci	.has_lcd_clk_src	=	true,
111362306a36Sopenharmony_ci};
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_cistatic const struct dss_features omap54xx_dss_feats = {
111662306a36Sopenharmony_ci	.model			=	DSS_MODEL_OMAP5,
111762306a36Sopenharmony_ci	.fck_div_max		=	64,
111862306a36Sopenharmony_ci	.fck_freq_max		=	209250000,
111962306a36Sopenharmony_ci	.dss_fck_multiplier	=	1,
112062306a36Sopenharmony_ci	.parent_clk_name	=	"dpll_per_x2_ck",
112162306a36Sopenharmony_ci	.ports			=	omap2plus_ports,
112262306a36Sopenharmony_ci	.num_ports		=	ARRAY_SIZE(omap2plus_ports),
112362306a36Sopenharmony_ci	.outputs		=	omap5_dss_supported_outputs,
112462306a36Sopenharmony_ci	.ops			=	&dss_ops_omap5,
112562306a36Sopenharmony_ci	.dispc_clk_switch	=	{ 9, 7 },
112662306a36Sopenharmony_ci	.has_lcd_clk_src	=	true,
112762306a36Sopenharmony_ci};
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_cistatic const struct dss_features am43xx_dss_feats = {
113062306a36Sopenharmony_ci	.model			=	DSS_MODEL_OMAP3,
113162306a36Sopenharmony_ci	.fck_div_max		=	0,
113262306a36Sopenharmony_ci	.fck_freq_max		=	200000000,
113362306a36Sopenharmony_ci	.dss_fck_multiplier	=	0,
113462306a36Sopenharmony_ci	.parent_clk_name	=	NULL,
113562306a36Sopenharmony_ci	.ports			=	omap2plus_ports,
113662306a36Sopenharmony_ci	.num_ports		=	ARRAY_SIZE(omap2plus_ports),
113762306a36Sopenharmony_ci	.outputs		=	am43xx_dss_supported_outputs,
113862306a36Sopenharmony_ci	.ops			=	&dss_ops_omap2_omap3,
113962306a36Sopenharmony_ci	.dispc_clk_switch	=	{ 0, 0 },
114062306a36Sopenharmony_ci	.has_lcd_clk_src	=	true,
114162306a36Sopenharmony_ci};
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_cistatic const struct dss_features dra7xx_dss_feats = {
114462306a36Sopenharmony_ci	.model			=	DSS_MODEL_DRA7,
114562306a36Sopenharmony_ci	.fck_div_max		=	64,
114662306a36Sopenharmony_ci	.fck_freq_max		=	209250000,
114762306a36Sopenharmony_ci	.dss_fck_multiplier	=	1,
114862306a36Sopenharmony_ci	.parent_clk_name	=	"dpll_per_x2_ck",
114962306a36Sopenharmony_ci	.ports			=	dra7xx_ports,
115062306a36Sopenharmony_ci	.num_ports		=	ARRAY_SIZE(dra7xx_ports),
115162306a36Sopenharmony_ci	.outputs		=	omap5_dss_supported_outputs,
115262306a36Sopenharmony_ci	.ops			=	&dss_ops_dra7,
115362306a36Sopenharmony_ci	.dispc_clk_switch	=	{ 9, 7 },
115462306a36Sopenharmony_ci	.has_lcd_clk_src	=	true,
115562306a36Sopenharmony_ci};
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_cistatic void __dss_uninit_ports(struct dss_device *dss, unsigned int num_ports)
115862306a36Sopenharmony_ci{
115962306a36Sopenharmony_ci	struct platform_device *pdev = dss->pdev;
116062306a36Sopenharmony_ci	struct device_node *parent = pdev->dev.of_node;
116162306a36Sopenharmony_ci	struct device_node *port;
116262306a36Sopenharmony_ci	unsigned int i;
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	for (i = 0; i < num_ports; i++) {
116562306a36Sopenharmony_ci		port = of_graph_get_port_by_id(parent, i);
116662306a36Sopenharmony_ci		if (!port)
116762306a36Sopenharmony_ci			continue;
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci		switch (dss->feat->ports[i]) {
117062306a36Sopenharmony_ci		case OMAP_DISPLAY_TYPE_DPI:
117162306a36Sopenharmony_ci			dpi_uninit_port(port);
117262306a36Sopenharmony_ci			break;
117362306a36Sopenharmony_ci		case OMAP_DISPLAY_TYPE_SDI:
117462306a36Sopenharmony_ci			sdi_uninit_port(port);
117562306a36Sopenharmony_ci			break;
117662306a36Sopenharmony_ci		default:
117762306a36Sopenharmony_ci			break;
117862306a36Sopenharmony_ci		}
117962306a36Sopenharmony_ci		of_node_put(port);
118062306a36Sopenharmony_ci	}
118162306a36Sopenharmony_ci}
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_cistatic int dss_init_ports(struct dss_device *dss)
118462306a36Sopenharmony_ci{
118562306a36Sopenharmony_ci	struct platform_device *pdev = dss->pdev;
118662306a36Sopenharmony_ci	struct device_node *parent = pdev->dev.of_node;
118762306a36Sopenharmony_ci	struct device_node *port;
118862306a36Sopenharmony_ci	unsigned int i;
118962306a36Sopenharmony_ci	int r;
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	for (i = 0; i < dss->feat->num_ports; i++) {
119262306a36Sopenharmony_ci		port = of_graph_get_port_by_id(parent, i);
119362306a36Sopenharmony_ci		if (!port)
119462306a36Sopenharmony_ci			continue;
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci		switch (dss->feat->ports[i]) {
119762306a36Sopenharmony_ci		case OMAP_DISPLAY_TYPE_DPI:
119862306a36Sopenharmony_ci			r = dpi_init_port(dss, pdev, port, dss->feat->model);
119962306a36Sopenharmony_ci			if (r)
120062306a36Sopenharmony_ci				goto error;
120162306a36Sopenharmony_ci			break;
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci		case OMAP_DISPLAY_TYPE_SDI:
120462306a36Sopenharmony_ci			r = sdi_init_port(dss, pdev, port);
120562306a36Sopenharmony_ci			if (r)
120662306a36Sopenharmony_ci				goto error;
120762306a36Sopenharmony_ci			break;
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci		default:
121062306a36Sopenharmony_ci			break;
121162306a36Sopenharmony_ci		}
121262306a36Sopenharmony_ci		of_node_put(port);
121362306a36Sopenharmony_ci	}
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	return 0;
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_cierror:
121862306a36Sopenharmony_ci	of_node_put(port);
121962306a36Sopenharmony_ci	__dss_uninit_ports(dss, i);
122062306a36Sopenharmony_ci	return r;
122162306a36Sopenharmony_ci}
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_cistatic void dss_uninit_ports(struct dss_device *dss)
122462306a36Sopenharmony_ci{
122562306a36Sopenharmony_ci	__dss_uninit_ports(dss, dss->feat->num_ports);
122662306a36Sopenharmony_ci}
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_cistatic int dss_video_pll_probe(struct dss_device *dss)
122962306a36Sopenharmony_ci{
123062306a36Sopenharmony_ci	struct platform_device *pdev = dss->pdev;
123162306a36Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
123262306a36Sopenharmony_ci	struct regulator *pll_regulator;
123362306a36Sopenharmony_ci	int r;
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	if (!np)
123662306a36Sopenharmony_ci		return 0;
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	if (of_property_read_bool(np, "syscon-pll-ctrl")) {
123962306a36Sopenharmony_ci		dss->syscon_pll_ctrl = syscon_regmap_lookup_by_phandle(np,
124062306a36Sopenharmony_ci			"syscon-pll-ctrl");
124162306a36Sopenharmony_ci		if (IS_ERR(dss->syscon_pll_ctrl)) {
124262306a36Sopenharmony_ci			dev_err(&pdev->dev,
124362306a36Sopenharmony_ci				"failed to get syscon-pll-ctrl regmap\n");
124462306a36Sopenharmony_ci			return PTR_ERR(dss->syscon_pll_ctrl);
124562306a36Sopenharmony_ci		}
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci		if (of_property_read_u32_index(np, "syscon-pll-ctrl", 1,
124862306a36Sopenharmony_ci				&dss->syscon_pll_ctrl_offset)) {
124962306a36Sopenharmony_ci			dev_err(&pdev->dev,
125062306a36Sopenharmony_ci				"failed to get syscon-pll-ctrl offset\n");
125162306a36Sopenharmony_ci			return -EINVAL;
125262306a36Sopenharmony_ci		}
125362306a36Sopenharmony_ci	}
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	pll_regulator = devm_regulator_get(&pdev->dev, "vdda_video");
125662306a36Sopenharmony_ci	if (IS_ERR(pll_regulator)) {
125762306a36Sopenharmony_ci		r = PTR_ERR(pll_regulator);
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci		switch (r) {
126062306a36Sopenharmony_ci		case -ENOENT:
126162306a36Sopenharmony_ci			pll_regulator = NULL;
126262306a36Sopenharmony_ci			break;
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci		case -EPROBE_DEFER:
126562306a36Sopenharmony_ci			return -EPROBE_DEFER;
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci		default:
126862306a36Sopenharmony_ci			DSSERR("can't get DPLL VDDA regulator\n");
126962306a36Sopenharmony_ci			return r;
127062306a36Sopenharmony_ci		}
127162306a36Sopenharmony_ci	}
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	if (of_property_match_string(np, "reg-names", "pll1") >= 0) {
127462306a36Sopenharmony_ci		dss->video1_pll = dss_video_pll_init(dss, pdev, 0,
127562306a36Sopenharmony_ci						     pll_regulator);
127662306a36Sopenharmony_ci		if (IS_ERR(dss->video1_pll))
127762306a36Sopenharmony_ci			return PTR_ERR(dss->video1_pll);
127862306a36Sopenharmony_ci	}
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	if (of_property_match_string(np, "reg-names", "pll2") >= 0) {
128162306a36Sopenharmony_ci		dss->video2_pll = dss_video_pll_init(dss, pdev, 1,
128262306a36Sopenharmony_ci						     pll_regulator);
128362306a36Sopenharmony_ci		if (IS_ERR(dss->video2_pll)) {
128462306a36Sopenharmony_ci			dss_video_pll_uninit(dss->video1_pll);
128562306a36Sopenharmony_ci			return PTR_ERR(dss->video2_pll);
128662306a36Sopenharmony_ci		}
128762306a36Sopenharmony_ci	}
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	return 0;
129062306a36Sopenharmony_ci}
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci/* DSS HW IP initialisation */
129362306a36Sopenharmony_cistatic const struct of_device_id dss_of_match[] = {
129462306a36Sopenharmony_ci	{ .compatible = "ti,omap2-dss", .data = &omap24xx_dss_feats },
129562306a36Sopenharmony_ci	{ .compatible = "ti,omap3-dss", .data = &omap3630_dss_feats },
129662306a36Sopenharmony_ci	{ .compatible = "ti,omap4-dss", .data = &omap44xx_dss_feats },
129762306a36Sopenharmony_ci	{ .compatible = "ti,omap5-dss", .data = &omap54xx_dss_feats },
129862306a36Sopenharmony_ci	{ .compatible = "ti,dra7-dss",  .data = &dra7xx_dss_feats },
129962306a36Sopenharmony_ci	{},
130062306a36Sopenharmony_ci};
130162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, dss_of_match);
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_cistatic const struct soc_device_attribute dss_soc_devices[] = {
130462306a36Sopenharmony_ci	{ .machine = "OMAP3430/3530", .data = &omap34xx_dss_feats },
130562306a36Sopenharmony_ci	{ .machine = "AM35??",        .data = &omap34xx_dss_feats },
130662306a36Sopenharmony_ci	{ .family  = "AM43xx",        .data = &am43xx_dss_feats },
130762306a36Sopenharmony_ci	{ /* sentinel */ }
130862306a36Sopenharmony_ci};
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_cistatic int dss_bind(struct device *dev)
131162306a36Sopenharmony_ci{
131262306a36Sopenharmony_ci	struct dss_device *dss = dev_get_drvdata(dev);
131362306a36Sopenharmony_ci	struct platform_device *drm_pdev;
131462306a36Sopenharmony_ci	struct dss_pdata pdata;
131562306a36Sopenharmony_ci	int r;
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	r = component_bind_all(dev, NULL);
131862306a36Sopenharmony_ci	if (r)
131962306a36Sopenharmony_ci		return r;
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	pm_set_vt_switch(0);
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	pdata.dss = dss;
132462306a36Sopenharmony_ci	drm_pdev = platform_device_register_data(NULL, "omapdrm", 0,
132562306a36Sopenharmony_ci						 &pdata, sizeof(pdata));
132662306a36Sopenharmony_ci	if (IS_ERR(drm_pdev)) {
132762306a36Sopenharmony_ci		component_unbind_all(dev, NULL);
132862306a36Sopenharmony_ci		return PTR_ERR(drm_pdev);
132962306a36Sopenharmony_ci	}
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	dss->drm_pdev = drm_pdev;
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	return 0;
133462306a36Sopenharmony_ci}
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_cistatic void dss_unbind(struct device *dev)
133762306a36Sopenharmony_ci{
133862306a36Sopenharmony_ci	struct dss_device *dss = dev_get_drvdata(dev);
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	platform_device_unregister(dss->drm_pdev);
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	component_unbind_all(dev, NULL);
134362306a36Sopenharmony_ci}
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_cistatic const struct component_master_ops dss_component_ops = {
134662306a36Sopenharmony_ci	.bind = dss_bind,
134762306a36Sopenharmony_ci	.unbind = dss_unbind,
134862306a36Sopenharmony_ci};
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_cistruct dss_component_match_data {
135162306a36Sopenharmony_ci	struct device *dev;
135262306a36Sopenharmony_ci	struct component_match **match;
135362306a36Sopenharmony_ci};
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_cistatic int dss_add_child_component(struct device *dev, void *data)
135662306a36Sopenharmony_ci{
135762306a36Sopenharmony_ci	struct dss_component_match_data *cmatch = data;
135862306a36Sopenharmony_ci	struct component_match **match = cmatch->match;
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	/*
136162306a36Sopenharmony_ci	 * HACK
136262306a36Sopenharmony_ci	 * We don't have a working driver for rfbi, so skip it here always.
136362306a36Sopenharmony_ci	 * Otherwise dss will never get probed successfully, as it will wait
136462306a36Sopenharmony_ci	 * for rfbi to get probed.
136562306a36Sopenharmony_ci	 */
136662306a36Sopenharmony_ci	if (strstr(dev_name(dev), "rfbi"))
136762306a36Sopenharmony_ci		return 0;
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	/*
137062306a36Sopenharmony_ci	 * Handle possible interconnect target modules defined within the DSS.
137162306a36Sopenharmony_ci	 * The DSS components can be children of an interconnect target module
137262306a36Sopenharmony_ci	 * after the device tree has been updated for the module data.
137362306a36Sopenharmony_ci	 * See also omapdss_boot_init() for compatible fixup.
137462306a36Sopenharmony_ci	 */
137562306a36Sopenharmony_ci	if (strstr(dev_name(dev), "target-module"))
137662306a36Sopenharmony_ci		return device_for_each_child(dev, cmatch,
137762306a36Sopenharmony_ci					     dss_add_child_component);
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	component_match_add(cmatch->dev, match, component_compare_dev, dev);
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	return 0;
138262306a36Sopenharmony_ci}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_cistatic int dss_probe_hardware(struct dss_device *dss)
138562306a36Sopenharmony_ci{
138662306a36Sopenharmony_ci	u32 rev;
138762306a36Sopenharmony_ci	int r;
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	r = dss_runtime_get(dss);
139062306a36Sopenharmony_ci	if (r)
139162306a36Sopenharmony_ci		return r;
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	dss->dss_clk_rate = clk_get_rate(dss->dss_clk);
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	/* Select DPLL */
139662306a36Sopenharmony_ci	REG_FLD_MOD(dss, DSS_CONTROL, 0, 0, 0);
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	dss_select_dispc_clk_source(dss, DSS_CLK_SRC_FCK);
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci#ifdef CONFIG_OMAP2_DSS_VENC
140162306a36Sopenharmony_ci	REG_FLD_MOD(dss, DSS_CONTROL, 1, 4, 4);	/* venc dac demen */
140262306a36Sopenharmony_ci	REG_FLD_MOD(dss, DSS_CONTROL, 1, 3, 3);	/* venc clock 4x enable */
140362306a36Sopenharmony_ci	REG_FLD_MOD(dss, DSS_CONTROL, 0, 2, 2);	/* venc clock mode = normal */
140462306a36Sopenharmony_ci#endif
140562306a36Sopenharmony_ci	dss->dsi_clk_source[0] = DSS_CLK_SRC_FCK;
140662306a36Sopenharmony_ci	dss->dsi_clk_source[1] = DSS_CLK_SRC_FCK;
140762306a36Sopenharmony_ci	dss->dispc_clk_source = DSS_CLK_SRC_FCK;
140862306a36Sopenharmony_ci	dss->lcd_clk_source[0] = DSS_CLK_SRC_FCK;
140962306a36Sopenharmony_ci	dss->lcd_clk_source[1] = DSS_CLK_SRC_FCK;
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	rev = dss_read_reg(dss, DSS_REVISION);
141262306a36Sopenharmony_ci	pr_info("OMAP DSS rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	dss_runtime_put(dss);
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	return 0;
141762306a36Sopenharmony_ci}
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_cistatic int dss_probe(struct platform_device *pdev)
142062306a36Sopenharmony_ci{
142162306a36Sopenharmony_ci	const struct soc_device_attribute *soc;
142262306a36Sopenharmony_ci	struct dss_component_match_data cmatch;
142362306a36Sopenharmony_ci	struct component_match *match = NULL;
142462306a36Sopenharmony_ci	struct dss_device *dss;
142562306a36Sopenharmony_ci	int r;
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	dss = kzalloc(sizeof(*dss), GFP_KERNEL);
142862306a36Sopenharmony_ci	if (!dss)
142962306a36Sopenharmony_ci		return -ENOMEM;
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	dss->pdev = pdev;
143262306a36Sopenharmony_ci	platform_set_drvdata(pdev, dss);
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	r = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
143562306a36Sopenharmony_ci	if (r) {
143662306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to set the DMA mask\n");
143762306a36Sopenharmony_ci		goto err_free_dss;
143862306a36Sopenharmony_ci	}
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	/*
144162306a36Sopenharmony_ci	 * The various OMAP3-based SoCs can't be told apart using the compatible
144262306a36Sopenharmony_ci	 * string, use SoC device matching.
144362306a36Sopenharmony_ci	 */
144462306a36Sopenharmony_ci	soc = soc_device_match(dss_soc_devices);
144562306a36Sopenharmony_ci	if (soc)
144662306a36Sopenharmony_ci		dss->feat = soc->data;
144762306a36Sopenharmony_ci	else
144862306a36Sopenharmony_ci		dss->feat = of_match_device(dss_of_match, &pdev->dev)->data;
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	/* Map I/O registers, get and setup clocks. */
145162306a36Sopenharmony_ci	dss->base = devm_platform_ioremap_resource(pdev, 0);
145262306a36Sopenharmony_ci	if (IS_ERR(dss->base)) {
145362306a36Sopenharmony_ci		r = PTR_ERR(dss->base);
145462306a36Sopenharmony_ci		goto err_free_dss;
145562306a36Sopenharmony_ci	}
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	r = dss_get_clocks(dss);
145862306a36Sopenharmony_ci	if (r)
145962306a36Sopenharmony_ci		goto err_free_dss;
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	r = dss_setup_default_clock(dss);
146262306a36Sopenharmony_ci	if (r)
146362306a36Sopenharmony_ci		goto err_put_clocks;
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	/* Setup the video PLLs and the DPI and SDI ports. */
146662306a36Sopenharmony_ci	r = dss_video_pll_probe(dss);
146762306a36Sopenharmony_ci	if (r)
146862306a36Sopenharmony_ci		goto err_put_clocks;
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	r = dss_init_ports(dss);
147162306a36Sopenharmony_ci	if (r)
147262306a36Sopenharmony_ci		goto err_uninit_plls;
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	/* Enable runtime PM and probe the hardware. */
147562306a36Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci	r = dss_probe_hardware(dss);
147862306a36Sopenharmony_ci	if (r)
147962306a36Sopenharmony_ci		goto err_pm_runtime_disable;
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	/* Initialize debugfs. */
148262306a36Sopenharmony_ci	r = dss_initialize_debugfs(dss);
148362306a36Sopenharmony_ci	if (r)
148462306a36Sopenharmony_ci		goto err_pm_runtime_disable;
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	dss->debugfs.clk = dss_debugfs_create_file(dss, "clk",
148762306a36Sopenharmony_ci						   dss_debug_dump_clocks, dss);
148862306a36Sopenharmony_ci	dss->debugfs.dss = dss_debugfs_create_file(dss, "dss", dss_dump_regs,
148962306a36Sopenharmony_ci						   dss);
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	/* Add all the child devices as components. */
149262306a36Sopenharmony_ci	r = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
149362306a36Sopenharmony_ci	if (r)
149462306a36Sopenharmony_ci		goto err_uninit_debugfs;
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	omapdss_gather_components(&pdev->dev);
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci	cmatch.dev = &pdev->dev;
149962306a36Sopenharmony_ci	cmatch.match = &match;
150062306a36Sopenharmony_ci	device_for_each_child(&pdev->dev, &cmatch, dss_add_child_component);
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	r = component_master_add_with_match(&pdev->dev, &dss_component_ops, match);
150362306a36Sopenharmony_ci	if (r)
150462306a36Sopenharmony_ci		goto err_of_depopulate;
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	return 0;
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_cierr_of_depopulate:
150962306a36Sopenharmony_ci	of_platform_depopulate(&pdev->dev);
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_cierr_uninit_debugfs:
151262306a36Sopenharmony_ci	dss_debugfs_remove_file(dss->debugfs.clk);
151362306a36Sopenharmony_ci	dss_debugfs_remove_file(dss->debugfs.dss);
151462306a36Sopenharmony_ci	dss_uninitialize_debugfs(dss);
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_cierr_pm_runtime_disable:
151762306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
151862306a36Sopenharmony_ci	dss_uninit_ports(dss);
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_cierr_uninit_plls:
152162306a36Sopenharmony_ci	if (dss->video1_pll)
152262306a36Sopenharmony_ci		dss_video_pll_uninit(dss->video1_pll);
152362306a36Sopenharmony_ci	if (dss->video2_pll)
152462306a36Sopenharmony_ci		dss_video_pll_uninit(dss->video2_pll);
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_cierr_put_clocks:
152762306a36Sopenharmony_ci	dss_put_clocks(dss);
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_cierr_free_dss:
153062306a36Sopenharmony_ci	kfree(dss);
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci	return r;
153362306a36Sopenharmony_ci}
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_cistatic void dss_remove(struct platform_device *pdev)
153662306a36Sopenharmony_ci{
153762306a36Sopenharmony_ci	struct dss_device *dss = platform_get_drvdata(pdev);
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	of_platform_depopulate(&pdev->dev);
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	component_master_del(&pdev->dev, &dss_component_ops);
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci	dss_debugfs_remove_file(dss->debugfs.clk);
154462306a36Sopenharmony_ci	dss_debugfs_remove_file(dss->debugfs.dss);
154562306a36Sopenharmony_ci	dss_uninitialize_debugfs(dss);
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	dss_uninit_ports(dss);
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	if (dss->video1_pll)
155262306a36Sopenharmony_ci		dss_video_pll_uninit(dss->video1_pll);
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	if (dss->video2_pll)
155562306a36Sopenharmony_ci		dss_video_pll_uninit(dss->video2_pll);
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	dss_put_clocks(dss);
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	kfree(dss);
156062306a36Sopenharmony_ci}
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_cistatic void dss_shutdown(struct platform_device *pdev)
156362306a36Sopenharmony_ci{
156462306a36Sopenharmony_ci	DSSDBG("shutdown\n");
156562306a36Sopenharmony_ci}
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_cistatic __maybe_unused int dss_runtime_suspend(struct device *dev)
156862306a36Sopenharmony_ci{
156962306a36Sopenharmony_ci	struct dss_device *dss = dev_get_drvdata(dev);
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	dss_save_context(dss);
157262306a36Sopenharmony_ci	dss_set_min_bus_tput(dev, 0);
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci	pinctrl_pm_select_sleep_state(dev);
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	return 0;
157762306a36Sopenharmony_ci}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_cistatic __maybe_unused int dss_runtime_resume(struct device *dev)
158062306a36Sopenharmony_ci{
158162306a36Sopenharmony_ci	struct dss_device *dss = dev_get_drvdata(dev);
158262306a36Sopenharmony_ci	int r;
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	pinctrl_pm_select_default_state(dev);
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	/*
158762306a36Sopenharmony_ci	 * Set an arbitrarily high tput request to ensure OPP100.
158862306a36Sopenharmony_ci	 * What we should really do is to make a request to stay in OPP100,
158962306a36Sopenharmony_ci	 * without any tput requirements, but that is not currently possible
159062306a36Sopenharmony_ci	 * via the PM layer.
159162306a36Sopenharmony_ci	 */
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	r = dss_set_min_bus_tput(dev, 1000000000);
159462306a36Sopenharmony_ci	if (r)
159562306a36Sopenharmony_ci		return r;
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci	dss_restore_context(dss);
159862306a36Sopenharmony_ci	return 0;
159962306a36Sopenharmony_ci}
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_cistatic const struct dev_pm_ops dss_pm_ops = {
160262306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(dss_runtime_suspend, dss_runtime_resume, NULL)
160362306a36Sopenharmony_ci	SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
160462306a36Sopenharmony_ci};
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_cistruct platform_driver omap_dsshw_driver = {
160762306a36Sopenharmony_ci	.probe		= dss_probe,
160862306a36Sopenharmony_ci	.remove_new	= dss_remove,
160962306a36Sopenharmony_ci	.shutdown	= dss_shutdown,
161062306a36Sopenharmony_ci	.driver         = {
161162306a36Sopenharmony_ci		.name   = "omapdss_dss",
161262306a36Sopenharmony_ci		.pm	= &dss_pm_ops,
161362306a36Sopenharmony_ci		.of_match_table = dss_of_match,
161462306a36Sopenharmony_ci		.suppress_bind_attrs = true,
161562306a36Sopenharmony_ci	},
161662306a36Sopenharmony_ci};
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci/* INIT */
161962306a36Sopenharmony_cistatic struct platform_driver * const omap_dss_drivers[] = {
162062306a36Sopenharmony_ci	&omap_dsshw_driver,
162162306a36Sopenharmony_ci	&omap_dispchw_driver,
162262306a36Sopenharmony_ci#ifdef CONFIG_OMAP2_DSS_DSI
162362306a36Sopenharmony_ci	&omap_dsihw_driver,
162462306a36Sopenharmony_ci#endif
162562306a36Sopenharmony_ci#ifdef CONFIG_OMAP2_DSS_VENC
162662306a36Sopenharmony_ci	&omap_venchw_driver,
162762306a36Sopenharmony_ci#endif
162862306a36Sopenharmony_ci#ifdef CONFIG_OMAP4_DSS_HDMI
162962306a36Sopenharmony_ci	&omapdss_hdmi4hw_driver,
163062306a36Sopenharmony_ci#endif
163162306a36Sopenharmony_ci#ifdef CONFIG_OMAP5_DSS_HDMI
163262306a36Sopenharmony_ci	&omapdss_hdmi5hw_driver,
163362306a36Sopenharmony_ci#endif
163462306a36Sopenharmony_ci};
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ciint __init omap_dss_init(void)
163762306a36Sopenharmony_ci{
163862306a36Sopenharmony_ci	return platform_register_drivers(omap_dss_drivers,
163962306a36Sopenharmony_ci					 ARRAY_SIZE(omap_dss_drivers));
164062306a36Sopenharmony_ci}
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_civoid omap_dss_exit(void)
164362306a36Sopenharmony_ci{
164462306a36Sopenharmony_ci	platform_unregister_drivers(omap_dss_drivers,
164562306a36Sopenharmony_ci				    ARRAY_SIZE(omap_dss_drivers));
164662306a36Sopenharmony_ci}
1647