diff options
Diffstat (limited to 'drivers/gpu/imx/dcss/dcss-blkctl.c')
-rw-r--r-- | drivers/gpu/imx/dcss/dcss-blkctl.c | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/drivers/gpu/imx/dcss/dcss-blkctl.c b/drivers/gpu/imx/dcss/dcss-blkctl.c new file mode 100644 index 000000000000..2f13b33dba35 --- /dev/null +++ b/drivers/gpu/imx/dcss/dcss-blkctl.c @@ -0,0 +1,143 @@ +/* + * Copyright 2017 NXP + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <linux/device.h> +#include <linux/io.h> +#include <linux/bitops.h> +#include <linux/of.h> +#include <linux/delay.h> +#include <soc/imx8/soc.h> + +#include "dcss-prv.h" +#include <video/imx-dcss.h> + +#define DCSS_BLKCTL_RESET_CTRL 0x00 +#define B_CLK_RESETN BIT(0) +#define APB_CLK_RESETN BIT(1) +#define P_CLK_RESETN BIT(2) +#define RTR_CLK_RESETN BIT(3) +#define HDMI_RESETN BIT(4) +#define DCSS_BLKCTL_CONTROL0 0x10 +#define HDMI_MIPI_CLK_SEL BIT(0) +#define DISPMIX_REFCLK_SEL_POS 4 +#define DISPMIX_REFCLK_SEL_MASK GENMASK(5, 4) +#define DISPMIX_PIXCLK_SEL BIT(8) +#define HDMI_SRC_SECURE_EN BIT(16) + +#define B0_SILICON_ID 0x20 + +static struct dcss_debug_reg blkctl_debug_reg[] = { + DCSS_DBG_REG(DCSS_BLKCTL_RESET_CTRL), + DCSS_DBG_REG(DCSS_BLKCTL_CONTROL0), +}; + +struct dcss_blkctl_priv { + struct dcss_soc *dcss; + void __iomem *base_reg; + + bool hdmi_output; + u32 clk_setting; +}; + +#ifdef CONFIG_DEBUG_FS +void dcss_blkctl_dump_regs(struct seq_file *s, void *data) +{ + struct dcss_soc *dcss = data; + int j; + + seq_puts(s, ">> Dumping BLKCTL:\n"); + for (j = 0; j < ARRAY_SIZE(blkctl_debug_reg); j++) + seq_printf(s, "%-35s(0x%04x) -> 0x%08x\n", + blkctl_debug_reg[j].name, + blkctl_debug_reg[j].ofs, + dcss_readl(dcss->blkctl_priv->base_reg + + blkctl_debug_reg[j].ofs)); +} +#endif + +static void dcss_blkctl_clk_reset(struct dcss_blkctl_priv *blkctl, + u32 assert, u32 deassert) +{ + if (assert) + dcss_clr(assert, blkctl->base_reg + DCSS_BLKCTL_RESET_CTRL); + + if (deassert) + dcss_set(deassert, blkctl->base_reg + DCSS_BLKCTL_RESET_CTRL); +} + +void dcss_blkctl_cfg(struct dcss_soc *dcss) +{ + struct dcss_blkctl_priv *blkctl = dcss->blkctl_priv; + + if (blkctl->hdmi_output) + dcss_writel((blkctl->clk_setting ^ HDMI_MIPI_CLK_SEL), + blkctl->base_reg + DCSS_BLKCTL_CONTROL0); + else + dcss_writel((blkctl->clk_setting ^ HDMI_MIPI_CLK_SEL) | + DISPMIX_PIXCLK_SEL, + blkctl->base_reg + DCSS_BLKCTL_CONTROL0); + + /* deassert clock domains resets */ + dcss_blkctl_clk_reset(blkctl, 0, 0xffffff); +} + +int dcss_blkctl_init(struct dcss_soc *dcss, unsigned long blkctl_base) +{ + struct device_node *node = dcss->dev->of_node; + int len; + const char *disp_dev; + struct dcss_blkctl_priv *blkctl; + + blkctl = devm_kzalloc(dcss->dev, sizeof(*blkctl), GFP_KERNEL); + if (!blkctl) + return -ENOMEM; + + blkctl->base_reg = devm_ioremap(dcss->dev, blkctl_base, SZ_4K); + if (!blkctl->base_reg) { + dev_err(dcss->dev, "unable to remap BLK CTRL base\n"); + return -ENOMEM; + } + + blkctl->dcss = dcss; + dcss->blkctl_priv = blkctl; + + disp_dev = of_get_property(node, "disp-dev", &len); + if (!disp_dev || !strncmp(disp_dev, "hdmi_disp", 9)) + blkctl->hdmi_output = true; + + if (imx8_get_soc_revision() >= B0_SILICON_ID) + blkctl->clk_setting = HDMI_MIPI_CLK_SEL; + + dcss_blkctl_cfg(dcss); + + return 0; +} + +void dcss_blkctl_exit(struct dcss_soc *dcss) +{ + /* assert clock domains resets */ + dcss_blkctl_clk_reset(dcss->blkctl_priv, + B_CLK_RESETN | APB_CLK_RESETN | P_CLK_RESETN | + HDMI_RESETN | RTR_CLK_RESETN, 0); +} + +/* disabled only by cold reset/reboot */ +void dcss_blkctl_hdmi_secure_src_en(struct dcss_soc *dcss) +{ + struct dcss_blkctl_priv *blkctl = dcss->blkctl_priv; + + dcss_set(HDMI_SRC_SECURE_EN, blkctl->base_reg + DCSS_BLKCTL_CONTROL0); +} +EXPORT_SYMBOL(dcss_blkctl_hdmi_secure_src_en); + |