| /* |
| * 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); |
| |